diff --git a/README.md b/README.md index 89b746a..4d8616f 100644 --- a/README.md +++ b/README.md @@ -35,15 +35,15 @@ Please refer to [_"Fooled by Randomness"_](https://en.wikipedia.org/wiki/Fooled_ # Requirements Supported Operating Systems and features: -| OS \ Feature | CI | gcc | clang | UT | WX | QT | R | -| ------------- | -- | --- | ----- | -- | -- | -- | -- | -| Debian stable | | ✓ | ✓ | ✓ | ✓ | | ✓ | -| Debian buster | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Ubuntu 21.04 | | ✓ | ✓ | ✓ | ✓ | | ✓ | -| Ubuntu 20.04 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Mac OSX 11 | ✓ | | ✓ | ✓ | ✓ | | ✓ | -| Mac OSX 10.15 | ✓ | | ✓ | ✓ | ✓ | | | -| Windows | ✓ | ✓ | | ✓ | | | | +| OS \ Feature | CI | gcc | clang | UT | WX | QT | Py | R | +| ------------- | -- | --- | ----- | -- | -- | -- | -- | -- | +| Debian stable | | ✓ | ✓ | ✓ | ✓ | | ✓ | ✓ | +| Debian buster | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Ubuntu 21.04 | | ✓ | ✓ | ✓ | ✓ | | ✓ | ✓ | +| Ubuntu 20.04 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Mac OSX 11 | ✓ | | ✓ | ✓ | ✓ | | ✓ | ✓ | +| Mac OSX 10.15 | ✓ | | ✓ | ✓ | ✓ | | ✓ | | +| Windows | ✓ | ✓ | | ✓ | | | ✓ | | Glossary: - CI = [Continuous Integration](https://github.com/mj-xmr/tsqsim/actions) @@ -51,6 +51,7 @@ Glossary: - UT = Unit Tests - WX = wxWidgets configuration application - QT = QT application (data viewer) +- Py = Python replacement for the QT app - R = bindings to R statistical framework # Quickstart diff --git a/src/lib-base/src/ConfigSym.cpp b/src/lib-base/src/ConfigSym.cpp index 883fdeb..47b1aff 100644 --- a/src/lib-base/src/ConfigSym.cpp +++ b/src/lib-base/src/ConfigSym.cpp @@ -160,7 +160,7 @@ EnjoLib::Str ConfigSym::GetDateFromToStr(bool lineBreak) const EnjoLib::Osstream oss; oss << dates.yearStart << "." << cma.MakeLeadingZeroes(dates.monthStart, 2); oss << (lineBreak ? "\n" : " - " ); - oss << dates.yearEnd << "." << cma.MakeLeadingZeroes(dates.monthEnd, 2) << Nl; + oss << dates.yearEnd << "." << cma.MakeLeadingZeroes(dates.monthEnd, 2); return oss.str(); } diff --git a/src/lib-base/src/ConfigTS.cpp b/src/lib-base/src/ConfigTS.cpp index 093ef12..c51d480 100644 --- a/src/lib-base/src/ConfigTS.cpp +++ b/src/lib-base/src/ConfigTS.cpp @@ -35,6 +35,7 @@ void ConfigTS::RegisterAndReadBools(EnjoLib::Istream & f) RegisterAndReadBool(f, crashOnRecoverableErrors, 0, "Crash on err", "Crash on recoverable errors"); RegisterAndReadBool(f, PLOT_SERIES, 1, "Plot series", "Plot output series after evaluation"); RegisterAndReadBool(f, PLOT_BASELINE, 1, "Plot baseline", "Plot baseline prediction in QT app"); + RegisterAndReadBool(f, PLOT_PYTHON, 0, "Plot with Python", "Plot the series in Python backend"); RegisterAndReadBool(f, MT_XFORM, 1, "MT xform", "Perform the transformations in a multithreaded way (still unstable)"); RegisterAndReadBool(f, MT_REPORT, 0, "MT report", "Generate report in multithreaded way (still unstable)"); RegisterAndReadBool(f, USE_VECTOR_PRED, 1, "Opti vec pred", "Use optimized vectored prediction"); diff --git a/src/lib-base/src/ConfigTS.h b/src/lib-base/src/ConfigTS.h index 4c8f0a2..7197e19 100644 --- a/src/lib-base/src/ConfigTS.h +++ b/src/lib-base/src/ConfigTS.h @@ -37,6 +37,7 @@ class ConfigTS : public ConfigBase bool crashOnRecoverableErrors = false; bool PLOT_SERIES = true; bool PLOT_BASELINE = true; + bool PLOT_PYTHON = false; bool MT_REPORT = false; bool MT_XFORM = false; bool USE_VECTOR_PRED = false; diff --git a/src/lib-base/src/MatplotLine.cpp b/src/lib-base/src/MatplotLine.cpp new file mode 100644 index 0000000..6a3b55a --- /dev/null +++ b/src/lib-base/src/MatplotLine.cpp @@ -0,0 +1,65 @@ +#include "MatplotLine.h" +#include "ConfigDirs.h" + +#include +#include +#include +#include +#include + +#include +using namespace EnjoLib; + +MatplotLine::MatplotLine(){} +MatplotLine::~MatplotLine(){} + +void MatplotLine::AddLine(const EnjoLib::VecD & line, const EnjoLib::Str & descr, const EnjoLib::Str & colour) +{ + Data dat; + dat.data = line; + dat.descr = descr; + dat.colour = colour; + m_dat.push_back(dat); +} + +void MatplotLine::Plot(const EnjoLib::Str & title) const +{ + const ConfigDirs cfgDirs; + const Str pyModuleIn = cfgDirs.DIR_SCRIPTS2 + "plot_line.py"; + { + Ifstream ifs(pyModuleIn); + } + const VecStr & linesModule = Tokenizer().GetLines(pyModuleIn); + const Str scriptOut = ToolsMixed().GetTmpDir() + "/plot_line_out.py"; + { + Ofstream ofs(scriptOut); + ofs << "import matplotlib" << Nl; + //ofs << "matplotlib.use('Agg')" << Nl; // For screenshots + + for (const Str & line : linesModule) + { + ofs << line << Nl; + } + + ofs << "lines = PlotLine()" << Nl; + ofs << "legend = ["; + for (const Data & dat : m_dat) + { + ofs << "'" << dat.descr << "', " << Nl; + } + ofs << "]" << Nl; + + + for (const Data & dat : m_dat) + { + ofs << dat.data.PrintPython("dat") << Nl; + ofs << "lines.addData1(dat, '" << dat.colour << "')" << Nl; + } + ofs << "lines.setupFigure('" << title << "', legend)" << Nl; + ofs << "lines.show()" << Nl; + ofs << "lines.close()" << Nl; + //ofs << "lines.demo()" << Nl; + } + + ToolsMixed().SystemCallWarn("python3 " + scriptOut, "MatplotLine::Plot()"); +} diff --git a/src/lib-base/src/MatplotLine.h b/src/lib-base/src/MatplotLine.h new file mode 100644 index 0000000..25affd4 --- /dev/null +++ b/src/lib-base/src/MatplotLine.h @@ -0,0 +1,29 @@ +#ifndef MATPLOTLINE_H +#define MATPLOTLINE_H + +#include +#include +#include + +class MatplotLine +{ + public: + MatplotLine(); + virtual ~MatplotLine(); + + void Plot(const EnjoLib::Str & title = "") const; + void AddLine(const EnjoLib::VecD & line, const EnjoLib::Str & descr, const EnjoLib::Str & colour = ""); + + protected: + + private: + struct Data + { + EnjoLib::VecD data; + EnjoLib::Str descr; + EnjoLib::Str colour; + }; + std::vector m_dat; +}; + +#endif // MATPLOTLINE_H diff --git a/src/tsqsim-lib/static/scripts/plot_line.py b/src/tsqsim-lib/static/scripts/plot_line.py new file mode 100644 index 0000000..3e6c580 --- /dev/null +++ b/src/tsqsim-lib/static/scripts/plot_line.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +""" +Created on Fri Oct 3 15:30:42 2014 + +@author: enjo +""" + +#from pylab import * +#import matplotlib +#matplotlib.use('Agg') +import matplotlib.pyplot as plt + + +class PlotLine: + def __init__(self): + self._fig, self._ax = plt.subplots(1, sharex=True) + self.width = 6 + + def addData(self, arg, data): + self._ax.plot(arg, data) + + def addData1(self, data, colour): + self._ax.plot(data, color=colour) + + def setupFigure(self, title, legend): + self._ax.grid() + self._ax.set_title(title) + self._ax.legend(legend) + + def show(self): + plt.show() + + def close(self): + plt.close(self._fig) + + def save(self, filename): + self.setupFigure() + self._fig.set_size_inches(self.width,6) + self._fig.savefig(filename, bbox_inches='tight', pad_inches=0, dpi=100) + +def demo(): + a = [1, 2, 3] + lines = PlotLine() + lines.addData1(a, "Blue") + lines.setupFigure('demo', ["Legend"]) + lines.show() + +#demo() diff --git a/src/tsqsim/src/App.cpp b/src/tsqsim/src/App.cpp index 865eb7a..34ca3c7 100644 --- a/src/tsqsim/src/App.cpp +++ b/src/tsqsim/src/App.cpp @@ -22,6 +22,8 @@ #include "TSUtil.h" #include "OptiHigh.h" #include "SimulatorTSFactoryImpl.h" +#include "MatplotLine.h" +#include "PredictorOutputType.h" #include #include @@ -40,7 +42,7 @@ void App::Run(const ConfigSym & confSymCmdLine) const { gcfgMan.Read(); - //const ConfigTS & confTS = *gcfgMan.cfgTS.get(); + const ConfigTS & confTS = *gcfgMan.cfgTS.get(); const ConfigTF2 & confTF2 = *gcfgMan.cfgTF2.get(); const ConfigOpti & confOpti = *gcfgMan.cfgOpti.get(); ConfigSym & confSym = *gcfgMan.cfgSym.get(); @@ -68,13 +70,17 @@ void App::Run(const ConfigSym & confSymCmdLine) const case OptiType::OPTI_TYPE_USE: { CorPtr sim = TSUtil().GetSim(per); + if (confTS.PLOT_PYTHON) + { + PlotPython(confSym, confTS, *sim); + } } break; case OptiType::OPTI_TYPE_XVALID: XValid(*symbol, per); break; } - {LOGL << confSym.GetDateFromToStr(false);} + {LOGL << confSym.GetDateFromToStr(false) << Nl;} if (confTF.REPEAT) { @@ -102,20 +108,20 @@ void App::XValid(const ISymbol & sym, const IPeriod & per) const const ConfigTS & confTS = *gcfgMan.cfgTS.get(); /// TODO: Allow override via console const PredictorFactory predFact; const PredictorType predType = confTS.GetPredType(); - + const TSInput tsin(per, confTS); - + CorPtr fun = tsFunFact.Create(tsin, tsFunType); - + OptimizerPred optiPred(predType, sym, per, predFact); const SimulatorTSFactory simFact; CorPtr sim = simFact.CreateTS(tsin, *fun); fun->SetSilent(); sim->SetSilent(); SimulatorTSFactoryImpl simFactImpl(tsin, *fun); - + OptiHigh().WalkForwardOptiIndiv(sym, per, 1, 1, optiPred, *sim, simFactImpl); - + sim->PrintOpti(); } @@ -133,3 +139,19 @@ void App::Optim(const ISymbol & sym, const IPeriod & per) const OptimizerPred optiPred(predType, sym, per, predFact); optiPred(); } + +void App::PlotPython(const ConfigSym & confSym, const ConfigTS & confTS, const ISimulatorTS & sim) const +{ + {LOGL << "Plot Python\n"; } + + MatplotLine plot; + plot.AddLine(sim.GetOutputSeries(PredictorOutputType::RECONSTRUCTION), "Signal", "Blue"); + if (confTS.PLOT_BASELINE) + { + plot.AddLine(sim.GetOutputSeries(PredictorOutputType::RECONSTRUCTION_PRED_BASELINE), "Prediction baseline", "Gray"); + } + plot.AddLine(sim.GetOutputSeries(PredictorOutputType::RECONSTRUCTION_PRED), "Prediction", "Green"); + + const Str title = confSym.symbol + " " + confSym.period + " " + confSym.GetDateFromToStr(false); + plot.Plot(title); +} diff --git a/src/tsqsim/src/App.h b/src/tsqsim/src/App.h index 4736c02..eda83f1 100644 --- a/src/tsqsim/src/App.h +++ b/src/tsqsim/src/App.h @@ -3,9 +3,11 @@ #include +class ConfigTS; class ConfigSym; class ISymbol; class IPeriod; +class ISimulatorTS; class App { @@ -16,6 +18,7 @@ class App void Run(const ConfigSym & cfgSymCmdLine) const; void Optim(const ISymbol & sym, const IPeriod & per) const; void XValid(const ISymbol & sym, const IPeriod & per) const; + void PlotPython(const ConfigSym & confSym, const ConfigTS & confTS, const ISimulatorTS & sim) const; protected: