SNAP Library 2.2, Developer Reference  2014-03-11 19:15:55
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 
00007 // Set path to gnuplot
00008 #if defined(GLib_WIN)
00009   TStr TGnuPlot::GnuPlotPath = "C:\\gnuplot";
00010   TStr TGnuPlot::GnuPlotFNm = "wgnuplot.exe";
00011 #elif defined(GLib_CYGWIN)
00012   TStr TGnuPlot::GnuPlotPath = "/usr/bin";
00013   TStr TGnuPlot::GnuPlotFNm = "gnuplot.exe";
00014 #elif defined(GLib_MACOSX) 
00015   TStr TGnuPlot::GnuPlotPath = "/opt/local/bin";
00016   TStr TGnuPlot::GnuPlotFNm = "gnuplot";
00017 #else 
00018   TStr TGnuPlot::GnuPlotPath = "/usr/bin";
00019   TStr TGnuPlot::GnuPlotFNm = "gnuplot";
00020 #endif
00021 
00022 // Determines the gnuplot version and the tics command syntax.
00023 // Gnuplot changed the syntax with version 4.2:
00024 // - before 4.2: set ticscale 2 1
00025 // - 4.2 and later: set tics 2
00026 int TGnuPlot::GetTics42() {
00027 #ifdef GLib_WIN
00028   return -1;
00029 #else   
00030   FILE* p;
00031   char Buf[1024];
00032   char Version[1024];
00033   size_t n;
00034   // get gnuplot version
00035   p = popen(TStr::Fmt("%s -V", TGnuPlot::GnuPlotFNm.CStr()).CStr(), "r");
00036   if (p == NULL) { // try running using the path
00037     p = popen(TStr::Fmt("%s/%s -V", TGnuPlot::GnuPlotPath.CStr(), TGnuPlot::GnuPlotFNm.CStr()).CStr(), "r");
00038     if (p == NULL) { return -1; }
00039   }
00040   n = fread(Buf, 1, 100, p);
00041   if (n <= 0) { return -1; }
00042   Buf[n] = '\0';
00043   pclose(p);
00044   //printf("Buf %d .%s.\n", n, Buf);
00045   n = sscanf(Buf, "gnuplot %s", Version);
00046   if (n <= 0) { return -1; }
00047   // printf("Version %d .%s.\n", n, Version);
00048   if ((strlen(Version) < 3) || (Version[1] != '.')) { return -1; }
00049   // test version < 4.2
00050   if ((Version[0] < '4') || ((Version[0] == '4') && (Version[2] < '2'))) {
00051     // printf("TGnuPlot::GetTics42 0\n");
00052     return 0;
00053   }
00054   // printf("TGnuPlot::GetTics42 1\n");
00055   return 1;
00056 #endif
00057 }
00058 
00059 int TGnuPlot::Tics42 = TGnuPlot::GetTics42();
00060 TStr TGnuPlot::DefPlotFNm = "GnuPlot.plt";
00061 TStr TGnuPlot::DefDataFNm = "GnuPlot.tab";
00062 
00063 TGnuPlot::TGpSeries::TGpSeries(const TGnuPlot::TGpSeries& Gps) :
00064   SeriesTy(Gps.SeriesTy), XYValV(Gps.XYValV), ZValV(Gps.ZValV),
00065   Label(Gps.Label), WithStyle(Gps.WithStyle), DataFNm(Gps.DataFNm),
00066   XCol(Gps.XCol), YCol(Gps.YCol), ZCol(Gps.ZCol) {
00067 }
00068 
00069 TGnuPlot::TGpSeries& TGnuPlot::TGpSeries::operator = (const TGnuPlot::TGpSeries& Gps) {
00070   if(this != &Gps) {
00071     SeriesTy = Gps.SeriesTy;
00072     XYValV = Gps.XYValV;  ZValV = Gps.ZValV;
00073     Label = Gps.Label;
00074     DataFNm = Gps.DataFNm;
00075     WithStyle = Gps.WithStyle;
00076     XCol = Gps.XCol;  YCol = Gps.YCol;  ZCol = Gps.ZCol;
00077   }
00078   return *this;
00079 }
00080 
00081 bool TGnuPlot::TGpSeries::operator < (const TGpSeries& Gps) const {
00082   return (XYValV < Gps.XYValV) || ((XYValV == Gps.XYValV) && (Label < Gps.Label));
00083 }
00084 
00085 TGnuPlot::TGnuPlot(const TStr& FileNm, const TStr& PlotTitle, const bool& Grid) :
00086  DataFNm(FileNm+".tab"), PlotFNm(FileNm+".plt"), Title(PlotTitle), LblX(), LblY(), ScaleTy(gpsAuto),
00087  YRange(0, 0), XRange(0, 0), SetGrid(Grid), SetPause(true),
00088  SeriesV(), MoreCmds() {
00089   IAssert(! FileNm.Empty());
00090 }
00091 
00092 TGnuPlot::TGnuPlot(const TStr& DataFileNm, const TStr& PlotFileNm, const TStr& PlotTitle, const bool& Grid) :
00093   DataFNm(DataFileNm.Empty() ? DefDataFNm : DataFileNm),
00094   PlotFNm(PlotFileNm.Empty() ? DefPlotFNm : PlotFileNm),
00095   Title(PlotTitle), LblX(), LblY(), ScaleTy(gpsAuto),
00096   YRange(0, 0), XRange(0, 0), SetGrid(Grid), SetPause(true), SeriesV(), MoreCmds() {
00097 }
00098 
00099 TGnuPlot::TGnuPlot(const TGnuPlot& GnuPlot) : DataFNm(GnuPlot.DataFNm), PlotFNm(GnuPlot.PlotFNm),
00100   Title(GnuPlot.Title), LblX(GnuPlot.LblX), LblY(GnuPlot.LblY), ScaleTy(GnuPlot.ScaleTy), YRange(GnuPlot.YRange),
00101   XRange(GnuPlot.XRange), SetGrid(GnuPlot.SetGrid), SetPause(GnuPlot.SetPause), SeriesV(GnuPlot.SeriesV),
00102   MoreCmds(GnuPlot.MoreCmds) {
00103 }
00104 
00105 TGnuPlot& TGnuPlot::operator = (const TGnuPlot& GnuPlot) {
00106   if (this != &GnuPlot) {
00107     DataFNm = GnuPlot.DataFNm;
00108     PlotFNm = GnuPlot.PlotFNm;
00109     Title = GnuPlot.Title;
00110     LblX = GnuPlot.LblX;
00111     LblY = GnuPlot.LblY;
00112     ScaleTy = GnuPlot.ScaleTy;
00113     YRange = GnuPlot.YRange;
00114     XRange = GnuPlot.XRange;
00115     SetGrid = GnuPlot.SetGrid;
00116     SetPause = GnuPlot.SetPause;
00117     SeriesV = GnuPlot.SeriesV;
00118     MoreCmds = GnuPlot.MoreCmds;
00119   }
00120   return *this;
00121 }
00122 
00123 TStr TGnuPlot::GetSeriesPlotStr(const int& SeriesId) {
00124   TChA PlotStr;
00125   TGpSeries& Series = SeriesV[SeriesId];
00126   if (SeriesId != 0) PlotStr += ",\\\n\t";
00127   if (Series.XCol >= 0) {
00128     PlotStr += "\"" + Series.DataFNm + "\" using " + TInt::GetStr(Series.XCol);
00129     if (Series.YCol != 0) { PlotStr += ":" + TInt::GetStr(Series.YCol); }
00130     if (Series.ZCol != 0) { PlotStr += ":" + TInt::GetStr(Series.ZCol); }
00131     else if (Series.SeriesTy==gpwFilledCurves) { PlotStr += ":(0)"; } // filled curves requres 3rd column
00132   } else {
00133     // function
00134     //IAssertR(Series.DataFNm.SearchCh('=') != -1, TStr::Fmt("Expression %s is not a function", Series.DataFNm.CStr()));
00135     PlotStr += Series.DataFNm;
00136   }
00137   PlotStr += " title \"" + Series.Label + "\"";
00138   // hard coded line style
00139   if (Series.WithStyle.Empty()) {
00140     if (Series.SeriesTy == gpwLines) Series.WithStyle = "lw 1";
00141     if (Series.SeriesTy == gpwPoints) Series.WithStyle = "pt 6"; // circles
00142     if (Series.SeriesTy == gpwLinesPoints) Series.WithStyle = "pt 6"; // circles
00143     if (Series.SeriesTy == gpwBoxes) Series.WithStyle = "fill solid 0.3";
00144   }
00145   PlotStr += " with " + GetSeriesTyStr(Series.SeriesTy) + " " + Series.WithStyle;
00146   return PlotStr;
00147 }
00148 
00149 //GP.AddFunc("2*x**-2+4", gpwLines, "2*x^-2+4");
00150 int TGnuPlot::AddFunc(const TStr& FuncStr, const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00151   const int Id = SeriesV.Len();
00152   TGpSeries Plot;
00153   Plot.SeriesTy = SeriesTy;
00154   Plot.Label = Label;
00155   if (! FuncStr.Empty()) { Plot.DataFNm = TStr::Fmt("f%d(x)=%s, f%d(x)", Id, FuncStr.CStr(), Id); }
00156   else { Plot.DataFNm = TStr::Fmt("f%d(x)", Id); }
00157   Plot.XCol = -1;
00158   Plot.WithStyle = Style;
00159   SeriesV.Add(Plot);
00160   return Id;
00161 }
00162 
00163 int TGnuPlot::AddPlot(const TStr& DataFNm, const int& ColY,
00164                       const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00165   return AddPlot(DataFNm, 0, ColY, SeriesTy, Label, Style);
00166 }
00167 
00168 int TGnuPlot::AddPlot(const TStr& DataFNm, const int& ColX, const int& ColY,
00169                       const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00170   IAssert(ColY > 0);  IAssert(ColX >= 0);
00171   TGpSeries Plot;
00172   Plot.SeriesTy = SeriesTy;
00173   Plot.Label = Label;
00174   Plot.DataFNm = DataFNm;  Plot.DataFNm.ChangeStrAll("\\", "\\\\");
00175   Plot.XCol = ColX;  Plot.YCol = ColY;  Plot.ZCol = 0;
00176   Plot.WithStyle = Style;
00177   SeriesV.Add(Plot);
00178   return SeriesV.Len() - 1;
00179 }
00180 
00181 int TGnuPlot::AddPlot(const TIntV& YValV, const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00182   TFltKdV XYValV(YValV.Len(), 0);
00183   for (int i = 0; i < YValV.Len(); i++) {
00184     XYValV.Add(TFltKd(TFlt(i+1), TFlt(YValV[i])));
00185   }
00186   return AddPlot(XYValV, SeriesTy, Label, Style);
00187 }
00188 
00189 int TGnuPlot::AddPlot(const TFltV& YValV, const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00190   TFltKdV XYValV(YValV.Len(), 0);
00191   for (int i = 0; i < YValV.Len(); i++) {
00192     XYValV.Add(TFltKd(TFlt(i+1), TFlt(YValV[i])));
00193   }
00194   return AddPlot(XYValV, SeriesTy, Label, Style);
00195 }
00196 
00197 int TGnuPlot::AddPlot(const TFltV& XValV, const TFltV& YValV, const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00198   IAssert(XValV.Len() == YValV.Len());
00199   TFltKdV XYValV(XValV.Len(), 0);
00200   for (int i = 0; i < YValV.Len(); i++) {
00201     XYValV.Add(TFltKd(TFlt(XValV[i]), TFlt(YValV[i])));
00202   }
00203   return AddPlot(XYValV, SeriesTy, Label, Style);
00204 }
00205 
00206 int TGnuPlot::AddPlot(const TIntPrV& XYValV, const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00207   TFltKdV XYFltValV(XYValV.Len(), 0);
00208   for (int i = 0; i < XYValV.Len(); i++) {
00209     XYFltValV.Add(TFltKd(TFlt(XYValV[i].Val1), TFlt(XYValV[i].Val2)));
00210   }
00211   return AddPlot(XYFltValV, SeriesTy, Label, Style);
00212 }
00213 
00214 int TGnuPlot::AddPlot(const TFltPrV& XYValV, const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00215   TFltKdV XYFltValV(XYValV.Len(), 0);
00216   for (int i = 0; i < XYValV.Len(); i++) {
00217     XYFltValV.Add(TFltKd(XYValV[i].Val1, XYValV[i].Val2));
00218   }
00219   return AddPlot(XYFltValV, SeriesTy, Label, Style);
00220 }
00221 
00222 int TGnuPlot::AddPlot(const TIntKdV& XYValV, const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00223   TFltKdV XYFltValV(XYValV.Len(), 0);
00224   for (int i = 0; i < XYValV.Len(); i++) {
00225     XYFltValV.Add(TFltKd(TFlt(XYValV[i].Key), TFlt(XYValV[i].Dat)));
00226   }
00227   return AddPlot(XYFltValV, SeriesTy, Label, Style);
00228 }
00229 
00230 int TGnuPlot::AddPlot(const TIntFltKdV& XYValV, const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00231   TFltKdV XYFltValV(XYValV.Len(), 0);
00232   for (int i = 0; i < XYValV.Len(); i++) {
00233     XYFltValV.Add(TFltKd(TFlt(XYValV[i].Key), TFlt(XYValV[i].Dat)));
00234   }
00235   return AddPlot(XYFltValV, SeriesTy, Label, Style);
00236 }
00237 
00238 int TGnuPlot::AddPlot(const TIntFltPrV& XYValV, const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00239   TFltKdV XYFltValV(XYValV.Len(), 0);
00240   for (int i = 0; i < XYValV.Len(); i++) {
00241     XYFltValV.Add(TFltKd(TFlt(XYValV[i].Val1), TFlt(XYValV[i].Val2)));
00242   }
00243   return AddPlot(XYFltValV, SeriesTy, Label, Style);
00244 }
00245 
00246 int TGnuPlot::AddPlot(const TFltKdV& XYValV, const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00247   if (XYValV.Empty()) {
00248     printf("***AddPlot: empty plot (%s) %s\n", DataFNm.CStr(), Title.CStr());
00249     return -1;
00250   }
00251   TGpSeries Plot;
00252   Plot.SeriesTy = SeriesTy;
00253   Plot.Label = Label;
00254   Plot.XYValV = XYValV;
00255   Plot.WithStyle = Style;
00256   SeriesV.Add(Plot);
00257   return SeriesV.Len() - 1;
00258 }
00259 
00260 int TGnuPlot::AddErrBar(const TFltTrV& XYDValV, const TStr& Label) {
00261   TFltKdV XYFltValV(XYDValV.Len(), 0);
00262   TFltV DeltaV(XYDValV.Len(), 0);
00263   for (int i = 0; i < XYDValV.Len(); i++) {
00264     XYFltValV.Add(TFltKd(XYDValV[i].Val1, XYDValV[i].Val2));
00265     DeltaV.Add(XYDValV[i].Val3);
00266   }
00267   return AddErrBar(XYFltValV, DeltaV, Label);
00268 }
00269 
00270 int TGnuPlot::AddErrBar(const TFltTrV& XYDValV, const TStr& DatLabel, const TStr& ErrLabel) {
00271   TFltKdV XYFltValV(XYDValV.Len(), 0);
00272   TFltV DeltaV(XYDValV.Len(), 0);
00273   for (int i = 0; i < XYDValV.Len(); i++) {
00274     XYFltValV.Add(TFltKd(XYDValV[i].Val1, XYDValV[i].Val2));
00275     DeltaV.Add(XYDValV[i].Val3);
00276   }
00277   const int PlotId = AddPlot(XYFltValV, gpwLinesPoints, DatLabel);
00278   AddErrBar(XYFltValV, DeltaV, ErrLabel);
00279   return PlotId;
00280 }
00281 
00282 int TGnuPlot::AddErrBar(const TFltV& YValV, const TFltV& DeltaYV, const TStr& Label) {
00283   IAssert(YValV.Len() == DeltaYV.Len());
00284   TFltKdV XYFltValV(YValV.Len(), 0);
00285   for (int i = 0; i < YValV.Len(); i++) {
00286     XYFltValV.Add(TFltKd(TFlt(i+1), YValV[i]));
00287   }
00288   return AddErrBar(XYFltValV, DeltaYV, Label);
00289 }
00290 
00291 int TGnuPlot::AddErrBar(const TFltV& XValV, const TFltV& YValV, const TFltV& DeltaYV, const TStr& Label) {
00292   IAssert(XValV.Len() == YValV.Len());
00293   IAssert(XValV.Len() == DeltaYV.Len());
00294   TFltKdV XYFltValV(XValV.Len(), 0);
00295   for (int i = 0; i < XValV.Len(); i++) {
00296     XYFltValV.Add(TFltKd(XValV[i], YValV[i]));
00297   }
00298   return AddErrBar(XYFltValV, DeltaYV, Label);
00299 }
00300 
00301 int TGnuPlot::AddErrBar(const TFltPrV& XYValV, const TFltV& DeltaYV, const TStr& Label) {
00302   TFltKdV XYFltValV(XYValV.Len(), 0);
00303   for (int i = 0; i < XYValV.Len(); i++) {
00304     XYFltValV.Add(TFltKd(XYValV[i].Val1, XYValV[i].Val2));
00305   }
00306   return AddErrBar(XYFltValV, DeltaYV, Label);
00307 }
00308 
00309 int TGnuPlot::AddErrBar(const TFltPrV& XYValV, const TFltV& DeltaV, const TStr& DatLabel, const TStr& ErrLabel) {
00310   TFltKdV XYFltValV(XYValV.Len(), 0);
00311   for (int i = 0; i < XYValV.Len(); i++) {
00312     XYFltValV.Add(TFltKd(XYValV[i].Val1, XYValV[i].Val2));
00313   }
00314   const int PlotId = AddPlot(XYFltValV, gpwLinesPoints, DatLabel);
00315   AddErrBar(XYFltValV, DeltaV, ErrLabel);
00316   return PlotId;
00317 }
00318 
00319 int TGnuPlot::AddErrBar(const TFltKdV& XYValV, const TFltV& DeltaYV, const TStr& Label) {
00320   if (XYValV.Empty()) {
00321     printf("***AddErrBar: empty plot (%s) %s\n", DataFNm.CStr(), Title.CStr());
00322     return -1;
00323   }
00324   IAssert(XYValV.Len() == DeltaYV.Len());
00325   TGpSeries Plot;
00326   Plot.SeriesTy = gpwErrBars;
00327   Plot.Label = Label;
00328   Plot.XYValV = XYValV;
00329   Plot.ZValV = DeltaYV;
00330   SeriesV.Add(Plot);
00331   return SeriesV.Len() - 1;
00332 }
00333 
00334 int TGnuPlot::AddLinFit(const int& PlotId, const TGpSeriesTy& SeriesTy, const TStr& Style) {
00335   if (PlotId < 0 || PlotId >= SeriesV.Len()) return -1;
00336   const TGpSeries& Plot = SeriesV[PlotId];
00337   if(Plot.XYValV.Empty()) return -1;
00338   const TFltKdV& XY = Plot.XYValV;
00339   double A, B, R2, SigA, SigB, Chi2;
00340   // linear fit
00341   TFltPrV XYPr;
00342   int s;
00343   for (s = 0; s < XY.Len(); s++) {
00344     XYPr.Add(TFltPr(XY[s].Key, XY[s].Dat));
00345   }
00346   TSpecFunc::LinearFit(XYPr, A, B, SigA, SigB, Chi2, R2);
00347   TStr StyleStr=Style;
00348   if (StyleStr.Empty()) { StyleStr = "linewidth 3"; }
00349   const int FitId = AddFunc(TStr::Fmt("%f+%f*x", A, B),
00350     SeriesTy, TStr::Fmt("%.4g + %.4g x  R^2:%.2g", A, B, R2), StyleStr);
00351   return FitId;
00352   /*SeriesV.Add();
00353   TGpSeries& NewPlot = SeriesV.Last();
00354   TFltKdV& EstXY = NewPlot.XYValV;
00355   for (s = 0; s < XY.Len(); s++) {
00356     EstXY.Add(TFltKd(XY[s].Key, A + B*XYPr[s].Val1));
00357   }
00358   NewPlot.Label = TStr::Fmt("%.4g + %.4g x  R^2:%.2g", A, B, R2);
00359   NewPlot.SeriesTy = SeriesTy;
00360   if (Style.Empty()) { NewPlot.WithStyle = "linewidth 3"; }
00361   else { NewPlot.WithStyle = Style; }
00362   return SeriesV.Len() - 1;*/
00363 }
00364 
00365 int TGnuPlot::AddPwrFit(const int& PlotId, const TGpSeriesTy& SeriesTy, const TStr& Style) {
00366   const int PlotId1 = AddPwrFit3(PlotId, SeriesTy);
00367   AddPwrFit2(PlotId, SeriesTy, 5.0);
00368   return PlotId1;
00369 }
00370 
00371 // linear fit on log-log scales{%
00372 int TGnuPlot::AddPwrFit1(const int& PlotId, const TGpSeriesTy& SeriesTy, const TStr& Style) {
00373   if (PlotId < 0 || PlotId >= SeriesV.Len()) return -1;
00374   const TGpSeries& Plot = SeriesV[PlotId];
00375   if(Plot.XYValV.Empty()) return -1;
00376   const TFltKdV& XY = Plot.XYValV;
00377   double A, B, R2, SigA, SigB, Chi2, MinY = TFlt::Mx, MinX = TFlt::Mx;
00378   // power fit
00379   TFltPrV XYPr;
00380   int s;
00381   for (s = 0; s < XY.Len(); s++) {
00382     if (XY[s].Key > 0) {
00383       XYPr.Add(TFltPr(XY[s].Key, XY[s].Dat)); 
00384       MinX = TMath::Mn(MinX, XY[s].Key());
00385       MinY = TMath::Mn(MinY, XY[s].Dat());
00386     }
00387   }
00388   MinY = TMath::Mn(1.0, MinY);
00389   TSpecFunc::PowerFit(XYPr, A, B, SigA, SigB, Chi2, R2);
00390   TStr StyleStr=Style;
00391   if (StyleStr.Empty()) { StyleStr = "linewidth 3"; }
00392   const int FitId = AddFunc(TStr::Fmt("%f*x**%f", A, B),
00393     SeriesTy, TStr::Fmt("%.1g * x^{%.4g}  R^2:%.2g", A, B, R2), StyleStr);
00394   return FitId;
00395   /*SeriesV.Add();
00396   TGpSeries& NewPlot = SeriesV.Last();
00397   const int FitId = SeriesV.Len() - 1;
00398   NewPlot.DataFNm = ;
00399   TFltKdV& EstXY = NewPlot.XYValV;
00400   for (s = 0; s < XYPr.Len(); s++) {
00401     const double YVal = A*pow(XYPr[s].Val1(), B);
00402     if (YVal < MinY) continue;
00403     EstXY.Add(TFltKd(XYPr[s].Val1, YVal));
00404   }
00405   NewPlot.Label = ;
00406   NewPlot.SeriesTy = SeriesTy;
00407   if (Style.Empty()) { NewPlot.WithStyle = "linewidth 3"; }
00408   else { NewPlot.WithStyle = Style; }
00409   //if (MinX < 5.0) MinX = 5.0;
00410   //AddPwrFit2(PlotId, SeriesTy, MinX);*/
00411 }
00412 
00413 // MLE power-coefficient
00414 int TGnuPlot::AddPwrFit2(const int& PlotId, const TGpSeriesTy& SeriesTy, const double& MinX, const TStr& Style) {
00415   const TGpSeries& Plot = SeriesV[PlotId];
00416   if(Plot.XYValV.Empty()) return -1;
00417   const TFltKdV& XY = Plot.XYValV;
00418   // power fit
00419   TFltPrV XYPr;
00420   double MinY = TFlt::Mx;
00421   for (int s = 0; s < XY.Len(); s++) {
00422     if (XY[s].Key > 0.0) {
00423       XYPr.Add(TFltPr(XY[s].Key, XY[s].Dat));
00424       MinY = TMath::Mn(MinY, XY[s].Dat());
00425     }
00426   }
00427   if (XYPr.Empty()) return -1;
00428   MinY = TMath::Mn(1.0, MinY);
00429   // determine the sign of power coefficient
00430   double CoefSign = 0.0;
00431   { double A, B, R2, SigA, SigB, Chi2;
00432   TSpecFunc::PowerFit(XYPr, A, B, SigA, SigB, Chi2, R2);
00433   CoefSign = B > 0.0 ? +1.0 : -1.0; }
00434   const double PowerCf = CoefSign * TSpecFunc::GetPowerCoef(XYPr, MinX);
00435   int Mid = (int) exp(log((double)XYPr.Len())/2.0);
00436   if (Mid >= XYPr.Len()) { Mid = XYPr.Len()-1; }
00437   const double MidX = XYPr[Mid].Val1();
00438   const double MidY = XYPr[Mid].Val2();
00439   const double B = MidY / pow(MidX, PowerCf);
00440   TStr StyleStr=Style;
00441   if (StyleStr.Empty()) { StyleStr = "linewidth 3"; }
00442   const int FitId = AddFunc(TStr::Fmt("%f*x**%f", B, PowerCf),
00443     SeriesTy, TStr::Fmt("MLE = x^{%.4g}", PowerCf), StyleStr);
00444   return FitId;
00445   /*SeriesV.Add();
00446   TGpSeries& NewPlot = SeriesV.Last();
00447   TFltKdV& XYFit = NewPlot.XYValV;
00448   XYFit.Gen(XYPr.Len(), 0);
00449   for (int s = 0; s < XYPr.Len(); s++) {
00450     const double XVal = XYPr[s].Val1;
00451     const double YVal = B * pow(XYPr[s].Val1(), PowerCf);
00452     if (YVal < MinY || XVal < MinX) continue;
00453     XYFit.Add(TFltKd(XVal, YVal));
00454   }
00455   NewPlot.Label = TStr::Fmt("PowerFit: %g", PowerCf);
00456   NewPlot.SeriesTy = SeriesTy;
00457   if (Style.Empty()) { NewPlot.WithStyle = "linewidth 3"; }
00458   else { NewPlot.WithStyle = Style; }
00459   return SeriesV.Len() - 1;*/
00460 }
00461 
00462 int TGnuPlot::AddPwrFit3(const int& PlotId, const TGpSeriesTy& SeriesTy, const double& MinX, const TStr& Style) {
00463   double Intercept, Slope, R2;
00464   return AddPwrFit3(PlotId, SeriesTy, MinX, Style, Intercept, Slope, R2);
00465 }
00466 
00467 // some kind of least squares power-law fitting that cutts the tail until the fit is good
00468 int TGnuPlot::AddPwrFit3(const int& PlotId, const TGpSeriesTy& SeriesTy, const double& MinX, const TStr& Style, double& Intercept, double& Slope, double& R2) {
00469   if (PlotId < 0 || PlotId >= SeriesV.Len()) return -1;
00470   const TGpSeries& Plot = SeriesV[PlotId];
00471   if(Plot.XYValV.Empty()) return -1;
00472   double A, B, SigA, SigB, Chi2, MinY=TFlt::Mx;
00473   const TFltKdV& XY = Plot.XYValV;
00474   //SeriesV.Add();
00475   //TGpSeries& NewPlot = SeriesV.Last();
00476   //TFltKdV& EstXY = NewPlot.XYValV;
00477   TFltPrV FitXY, NewFitXY;
00478   for (int s = 0; s < XY.Len(); s++) {
00479     if (XY[s].Key > 0 && XY[s].Key >= MinX) {
00480       FitXY.Add(TFltPr(XY[s].Key, XY[s].Dat)); 
00481       MinY = TMath::Mn(MinY, XY[s].Dat());
00482     }
00483   }
00484   MinY = TMath::Mn(1.0, MinY);
00485   // power fit (if tail is too fat, cut everything where
00486   // extrapolation sets the value < MinY
00487   while (true) {
00488     TSpecFunc::PowerFit(FitXY, A, B, SigA, SigB, Chi2, R2);
00489     NewFitXY.Clr(false);
00490     //EstXY.Clr(false);
00491     for (int s = 0; s < FitXY.Len(); s++) {
00492       const double YVal = A*pow(FitXY[s].Val1(), B);
00493       if (YVal < MinY) continue;
00494       //EstXY.Add(TFltKd(FitXY[s].Val1, YVal));
00495       NewFitXY.Add(TFltPr(FitXY[s].Val1, FitXY[s].Val2));
00496     }
00497     if (NewFitXY.Len() < 10 || FitXY.Last().Val1 < 1.2 * NewFitXY.Last().Val1) { break; }
00498     else { FitXY.Swap(NewFitXY); }
00499   }
00500   TStr StyleStr=Style;
00501   if (StyleStr.Empty()) { StyleStr = "linewidth 3"; }
00502   const int FitId = AddFunc(TStr::Fmt("%f*x**%f", A, B),
00503     SeriesTy, TStr::Fmt("%.1g * x^{%.4g}  R^2:%.2g", A, B, R2), StyleStr);
00504   return FitId;
00505   /*NewPlot.Label = TStr::Fmt("%.1g * x^{%.4g}  R^2:%.2g", A, B, R2);
00506   Intercept = A;
00507   Slope = B;
00508   NewPlot.SeriesTy = SeriesTy;
00509   if (Style.Empty()) { NewPlot.WithStyle = "linewidth 3"; }
00510   else { NewPlot.WithStyle = Style; }
00511   return SeriesV.Len() - 1;*/
00512 }
00513 
00514 int TGnuPlot::AddLogFit(const int& PlotId, const TGpSeriesTy& SeriesTy, const TStr& Style) {
00515   const TGpSeries& Plot = SeriesV[PlotId];
00516   if(Plot.XYValV.Empty()) return -1;
00517   const TFltKdV& XY = Plot.XYValV;
00518   double A, B, R2, SigA, SigB, Chi2;
00519   // power fit
00520   TFltPrV XYPr;
00521   int s;
00522   for (s = 0; s < XY.Len(); s++) {
00523     if (XY[s].Key > 0) {
00524       XYPr.Add(TFltPr(XY[s].Key, XY[s].Dat)); } 
00525   }
00526   TSpecFunc::LogFit(XYPr, A, B, SigA, SigB, Chi2, R2);
00527   TStr StyleStr=Style;
00528   if (StyleStr.Empty()) { StyleStr = "linewidth 3"; }
00529   const int FitId = AddFunc(TStr::Fmt("%f+%f*log(x)", A, B),
00530     SeriesTy, TStr::Fmt("%.4g + %.4g log(x)  R^2:%.2g", A, B, R2), StyleStr);
00531   return FitId;
00532   /*SeriesV.Add();
00533   TGpSeries& NewPlot = SeriesV.Last();
00534   TFltKdV& EstXY = NewPlot.XYValV;
00535   for (s = 0; s < XYPr.Len(); s++) {
00536     EstXY.Add(TFltKd(XYPr[s].Val1, A+B*log((double)XYPr[s].Val1)));
00537   }
00538   NewPlot.Label = TStr::Fmt("%.4g + %.4g log(x)  R^2:%.2g", A, B, R2);
00539   NewPlot.SeriesTy = SeriesTy;
00540   if (Style.Empty()) { NewPlot.WithStyle = "linewidth 3"; }
00541   else { NewPlot.WithStyle = Style; }
00542   return SeriesV.Len() - 1;*/
00543 }
00544 
00545 int TGnuPlot::AddExpFit(const int& PlotId, const TGpSeriesTy& SeriesTy, const double& FitXOffset, const TStr& Style) {
00546   const TGpSeries& Plot = SeriesV[PlotId];
00547   if(Plot.XYValV.Empty()) return -1;
00548   const TFltKdV& XY = Plot.XYValV;
00549   double A, B, R2, SigA, SigB, Chi2;
00550   // power fit
00551   TFltPrV XYPr;
00552   int s;
00553   for (s = 0; s < XY.Len(); s++) {
00554     if (XY[s].Key-FitXOffset > 0) {
00555       XYPr.Add(TFltPr(XY[s].Key-FitXOffset, XY[s].Dat)); } 
00556   }
00557   TSpecFunc::ExpFit(XYPr, A, B, SigA, SigB, Chi2, R2);
00558   TStr Label, StyleStr=Style;
00559   if (FitXOffset == 0) { Label = TStr::Fmt("%.4g exp(%.4g x)  R^2:%.2g", A, B, R2); }
00560   else { Label = TStr::Fmt("%.4g exp(%.4g x - %g)  R^2:%.2g", A, B, FitXOffset, R2); }
00561   if (StyleStr.Empty()) { StyleStr = "linewidth 3"; }
00562   const int FitId = AddFunc(TStr::Fmt("%f*exp(%f*x-%f)", A, B, FitXOffset),
00563     SeriesTy, Label, StyleStr);
00564   return FitId;
00565   /*SeriesV.Add();
00566   TGpSeries& NewPlot = SeriesV.Last();
00567   TFltKdV& EstXY = NewPlot.XYValV;
00568   for (s = 0; s < XYPr.Len(); s++) {
00569     EstXY.Add(TFltKd(XYPr[s].Val1+FitXOffset, A*exp(B*XYPr[s].Val1)));
00570   }
00571   NewPlot.SeriesTy = SeriesTy;
00572   if (Style.Empty()) { NewPlot.WithStyle = "linewidth 3"; }
00573   else { NewPlot.WithStyle = Style; }
00574   return SeriesV.Len() - 1;*/
00575 }
00576 
00577 void TGnuPlot::SavePng(const TStr& FNm, const int& SizeX, const int& SizeY, const TStr& Comment, const TStr& Terminal) {
00578   if (Terminal.Empty()) {
00579     //#ifdef GLib_WIN
00580     //#ifndef GLib_MACOSX  // The standard GNUPlot for MacOS does not support PNG (Jure: actually version 4.6 DOES!)
00581     AddCmd(TStr::Fmt("set terminal png size %d,%d", SizeX, SizeY));
00582     AddCmd(TStr::Fmt("set output '%s'", FNm.CStr()));
00583     //#else // EPS
00584     //AddCmd("set terminal postscript eps 10 enhanced color");
00585     //AddCmd(TStr::Fmt("set output '%s%s.eps'", FNm.GetFPath().CStr(), FNm.GetFMid().CStr()));
00586     //#endif
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   // try running gnuplot 
00866   if (system(TStr::Fmt("%s %s", GnuPlotFNm.CStr(), PlotFNm.CStr()).CStr())==0) { return; }
00867   if (! GnuPlotPath.Empty()) { 
00868     #if defined(GLib_WIN)
00869     if (system(TStr::Fmt("%s\\%s %s", GnuPlotPath.CStr(), GnuPlotFNm.CStr(), PlotFNm.CStr()).CStr())==0) { return; }
00870     #else
00871     if (system(TStr::Fmt("%s/%s %s", GnuPlotPath.CStr(), GnuPlotFNm.CStr(), PlotFNm.CStr()).CStr())==0) { return; }
00872     #endif
00873   }
00874   //Old
00875   //#if defined(GLib_WIN)
00876   //if (system(TStr::Fmt(".\\%s %s", GpFNm.CStr(), PlotFNm.CStr()).CStr())==0) { return; }
00877   //#else
00878   //if (system(TStr::Fmt("./%s %s", GpFNm.CStr(), PlotFNm.CStr()).CStr())==0) { return; }
00879   //#endif
00880   //if (system(TStr::Fmt("%s%s %s", GpPath.CStr(), GpFNm.CStr(), PlotFNm.CStr()).CStr())==0) { return; }
00881   //FailR(TStr::Fmt("Cat not find GnuPlot (%s) for plot %s. Set the PATH.", GpFNm.CStr(), PlotFNm.CStr()).CStr());
00882   //ErrNotify(TStr::Fmt("Cat not find GnuPlot (%s) for plot %s. Set the PATH.", GpFNm.CStr(), PlotFNm.CStr()).CStr());
00883   fprintf(stderr, "[%s:%d] Cat not find GnuPlot (%s) for plot %s. Set the $$PATH variable or TGnuPlot::GnuPlotPath. (%s)\n", __FILE__, __LINE__, GnuPlotFNm.CStr(), PlotFNm.CStr(), TGnuPlot::GnuPlotPath.CStr());
00884 }