Skip to content

Commit 4b0d352

Browse files
authored
Seasonal decomposition + wx UI (#64)
1 parent b446e9a commit 4b0d352

File tree

12 files changed

+129
-15
lines changed

12 files changed

+129
-15
lines changed

src/lib-base/src/CLI.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ EnjoLib::Result<CLIResult> CLI::GetConfigs(int argc, char ** argv) const
2424
const char * OPT_SYMBOL = "sym";
2525
const char * OPT_PERIOD = "per";
2626
const char * OPT_LAGS = "lags";
27+
const char * OPT_PER_SEASONAL = "per-easonal";
28+
2729

2830
EnjoLib::ProgramOptionsState popState;
2931
////popState.AddStr(OPT_PLUGIN, "Plugin name");
@@ -34,7 +36,9 @@ EnjoLib::Result<CLIResult> CLI::GetConfigs(int argc, char ** argv) const
3436
popState.AddStr(OPT_SYMBOL, "Symbol name");
3537
popState.AddStr(OPT_PERIOD, "Period name");
3638

37-
popState.AddInt(OPT_LAGS, ConfigTS::DESCR_PLOT_LAGS_NUM);
39+
popState.AddInt(OPT_LAGS, ConfigTS::DESCR_PLOT_LAGS_NUM);
40+
popState.AddInt(OPT_PER_SEASONAL, ConfigTS::DESCR_PLOT_PERIOD_NUM);
41+
3842

3943
popState.ReadArgs(argc, argv);
4044
const EnjoLib::ProgramOptions pops(popState);
@@ -75,6 +79,7 @@ EnjoLib::Result<CLIResult> CLI::GetConfigs(int argc, char ** argv) const
7579
confSym.period = pops.GetStrFromMap(OPT_PERIOD);
7680

7781
confTS.PLOT_LAGS_NUM = pops.GetIntFromMap(OPT_LAGS);
82+
confTS.PLOT_PERIOD_NUM = pops.GetIntFromMap(OPT_PER_SEASONAL);
7883

7984
//auto pluginName = pops.GetStrFromMap (OPT_PLUGIN);
8085

src/lib-base/src/ConfigTS.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ void ConfigTS::RegisterAndReadInts(EnjoLib::Istream & f)
4747
RegisterAndReadInt (f, PRED_TYPE, 0);
4848
RegisterAndReadInt (f, PRICE_TYPE, 0);
4949
RegisterAndReadInt (f, PLOT_LAGS_NUM, 30);
50+
RegisterAndReadInt (f, PLOT_PERIOD_NUM, 30);
5051
}
5152
void ConfigTS::RegisterAndReadFloats(EnjoLib::Istream & f)
5253
{
@@ -84,8 +85,8 @@ void ConfigTS::UpdateFromOther(const ConfigTS & cfgTSCmdLine)
8485
{
8586
PLOT_LAGS_NUM = cfgTSCmdLine.PLOT_LAGS_NUM;
8687
}
87-
else
88+
if (cfgTSCmdLine.PLOT_PERIOD_NUM > 0)
8889
{
89-
PLOT_LAGS_NUM = 30;
90+
PLOT_PERIOD_NUM = cfgTSCmdLine.PLOT_PERIOD_NUM;
9091
}
9192
}

src/lib-base/src/ConfigTS.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class ConfigTS : public ConfigBase
4848
long int PRED_TYPE = 0;
4949
long int PRICE_TYPE = 0;
5050
long int PLOT_LAGS_NUM = 30; constexpr static const char * DESCR_PLOT_LAGS_NUM = "Number of lags for ACF/PACF plot";
51+
long int PLOT_PERIOD_NUM = 30; constexpr static const char * DESCR_PLOT_PERIOD_NUM = "Seasonal period for seasonal decomposition plot";
5152

5253
protected:
5354
EnjoLib::Str GetFileNameProt() const override;

src/lib-base/src/MatplotACF.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <Ios/Osstream.hpp>
55
#include <Ios/Ofstream.hpp>
66
#include <Ios/Ifstream.hpp>
7+
#include <Util/CoutBuf.hpp>
78
#include <Util/Tokenizer.hpp>
89
#include <Util/AlgoSTDIVec.hpp>
910
#include <Util/ToolsMixed.hpp>
@@ -14,13 +15,14 @@ using namespace EnjoLib;
1415
MatplotACF::MatplotACF(){}
1516
MatplotACF::~MatplotACF(){}
1617

17-
void MatplotACF::Plot(const EnjoLib::VecD & dat, int lags, const EnjoLib::Str & title) const
18+
void MatplotACF::Plot(const EnjoLib::VecD & dat, int lags, int periodSeasonal, const EnjoLib::Str & title) const
1819
{
1920
const ConfigDirs cfgDirs;
2021
const Str pyModuleIn = cfgDirs.DIR_SCRIPTS2 + "plot_acf_pacf.py";
2122
{
2223
Ifstream ifs(pyModuleIn);
2324
}
25+
LOGL << "Reading file: " << pyModuleIn << Nl;
2426
const VecStr & linesModule = Tokenizer().GetLines(pyModuleIn);
2527
const Str scriptOut = ToolsMixed().GetTmpDir() + "/plot_acf_pacf_out.py";
2628
{
@@ -38,6 +40,7 @@ void MatplotACF::Plot(const EnjoLib::VecD & dat, int lags, const EnjoLib::Str &
3840
ofs << reversed.PrintPython("dat") << Nl;
3941
ofs << "plotACF(dat, " << lags << ", '" << title << "')" << Nl;
4042
ofs << "plotPACF(dat, " << lags << ", '" << title << "')" << Nl;
43+
ofs << "plotSeasonalDecomposition(dat, " << periodSeasonal << ", '" << title << "')" << Nl; /// TODO: Different lags for seasonality. It's the period. Do in wx.
4144
}
4245

4346
ToolsMixed().SystemCallWarn("python3 " + scriptOut, "MatplotACF::Plot()");

src/lib-base/src/MatplotACF.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class MatplotACF
1010
MatplotACF();
1111
virtual ~MatplotACF();
1212

13-
void Plot(const EnjoLib::VecD & line, int lags, const EnjoLib::Str & title = "") const;
13+
void Plot(const EnjoLib::VecD & line, int lags, int periodSeasonal, const EnjoLib::Str & title = "") const;
1414

1515
protected:
1616

src/tsqsim-lib/static/scripts/plot_acf_pacf.py

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
1717
#register_matplotlib_converters()
1818
from statsmodels.tsa.stattools import acf, pacf
19+
from statsmodels.tsa.seasonal import seasonal_decompose
1920

2021

2122
def plotACF(data, lags, title):
@@ -32,6 +33,9 @@ def plotPACF(data, lags, title):
3233
if lags > length:
3334
lags = length
3435
x = list(range(lags))
36+
if length > len(x):
37+
y = y[:len(x)]
38+
length = len(y)
3539
print(len(x))
3640
print(length)
3741
plt.bar(x, y)
@@ -41,6 +45,38 @@ def plotPACF(data, lags, title):
4145
plt.ylabel("Autocorrelation")
4246
plt.title("Partial Autocorr. (" + str(lags) + ") " + title)
4347
plt.show()
48+
49+
def plotSeasonalDecomposition(data, period, title, model='constant'):
50+
result = seasonal_decompose(data, model=model, period=period)
51+
num_plots = 4
52+
fig, axs = plt.subplots(num_plots)
53+
#fig.suptitle('Vertically stacked subplots')
54+
#print(result.seasonal)
55+
#plt.plot(result.observed)
56+
axs[0].plot(result.observed)
57+
axs[0].set_ylabel('observed')
58+
axs[1].plot(result.seasonal)
59+
axs[1].set_ylabel('seasonal')
60+
axs[2].plot(result.trend)
61+
axs[2].set_ylabel('trend')
62+
axs[3].plot(result.resid)
63+
axs[3].set_ylabel('residuals')
64+
#axs[4].plot(result.weights)
65+
#fig = result.plot()
66+
#fig.set_size_inches(12, 9)
67+
68+
for i in range(num_plots):
69+
axs[i].grid()
70+
71+
#axs[0].plot(data)
72+
#axs[1].plot(data)
73+
#fig.show()
74+
#plt.plot(result.seasonal)
75+
#plt.plot(result.trend)
76+
77+
plt.show()
78+
79+
4480

4581
def demo():
4682
#df_ice_cream = pd.read_csv('ice_cream.csv')
@@ -60,9 +96,13 @@ def demo():
6096
#print(df_ice_cream.head())
6197
#acf_plot = plot_acf(df_ice_cream.production, lags=100)
6298

63-
a = [1, 2, 3, 4, 5, 6]
64-
plotACF(a, 4, "demo")
65-
plotPACF(a, 4, "demo")
99+
a = range(1, 50)
100+
lags = 20
101+
period = 10
102+
title = 'demo'
103+
#plotACF(a, lags, title)
104+
#plotPACF(a, lags, title)
105+
plotSeasonalDecomposition(a, period, title, 'trend')
66106
#obj = pd.plotting.autocorrelation_plot(df_ice_cream.production)
67107
#plt.show()
68108

src/tsqsim/src/App.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,11 @@ void App::PlotPythonACF(const ConfigSym & confSym, const ConfigTS & confTS, cons
167167
{
168168
{LOGL << "Plot Python ACF\n"; }
169169

170-
const int lags = confTS.PLOT_LAGS_NUM; // TODO: Make user's choice
170+
const int lags = confTS.PLOT_LAGS_NUM;
171+
const int per = confTS.PLOT_PERIOD_NUM;
171172
const MatplotACF plot;
172173
const Str title = ": " + GetTitle(confSym);
173-
plot.Plot(sim.GetOutputSeries(PredictorOutputType::SERIES), lags, title);
174+
plot.Plot(sim.GetOutputSeries(PredictorOutputType::SERIES), lags, per, title);
174175
}
175176

176177
Str App::GetTitle(const ConfigSym & confSym) const

src/wxConfQT/src/DialogTS.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//*)
1313
#endif
1414
//(*InternalHeaders(DialogTS)
15+
#include <wx/spinctrl.h>
1516
//*)
1617

1718
//(*IdInit(DialogTS)
@@ -27,6 +28,8 @@ const long DialogTS::ID_BUTTON6 = wxNewId();
2728
const long DialogTS::ID_CHOICE1 = wxNewId();
2829
const long DialogTS::ID_CHOICE2 = wxNewId();
2930
const long DialogTS::ID_CHECKBOX12 = wxNewId();
31+
const long DialogTS::ID_SPINCTRL1 = wxNewId();
32+
const long DialogTS::ID_SPINCTRL2 = wxNewId();
3033
//*)
3134

3235
BEGIN_EVENT_TABLE(DialogTS,wxDialog)
@@ -47,6 +50,7 @@ DialogTS::DialogTS(wxWindow* parent,wxWindowID id)
4750
wxStaticBoxSizer* StaticBoxSizer3;
4851
wxStaticBoxSizer* StaticBoxSizer4;
4952
wxStaticBoxSizer* StaticBoxSizer5;
53+
wxStaticBoxSizer* StaticBoxSizer6;
5054

5155
Create(parent, id, _T("Time Series Analysis"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE, _T("id"));
5256
BoxSizer1 = new wxBoxSizer(wxVERTICAL);
@@ -95,6 +99,16 @@ DialogTS::DialogTS(wxWindow* parent,wxWindowID id)
9599
m_chkTechs->SetValue(true);
96100
m_chkTechs->Hide();
97101
m_sizerBools->Add(m_chkTechs, 0, wxEXPAND, 5);
102+
StaticBoxSizer6 = new wxStaticBoxSizer(wxHORIZONTAL, this, _T("Lags ACF/PACF + Seasonal Period"));
103+
m_spinLagACF = new wxSpinCtrl(this, ID_SPINCTRL1, _T("30"), wxDefaultPosition, wxSize(110,-1), 0, 1, 100, 30, _T("ID_SPINCTRL1"));
104+
m_spinLagACF->SetValue(_T("30"));
105+
m_spinLagACF->SetToolTip(_T("Lag ACF/PACF"));
106+
StaticBoxSizer6->Add(m_spinLagACF, 0, wxALL|wxEXPAND, 5);
107+
m_spinPeriodSeasonal = new wxSpinCtrl(this, ID_SPINCTRL2, _T("30"), wxDefaultPosition, wxSize(110,-1), 0, 1, 100, 30, _T("ID_SPINCTRL2"));
108+
m_spinPeriodSeasonal->SetValue(_T("30"));
109+
m_spinPeriodSeasonal->SetToolTip(_T("Seasonal period"));
110+
StaticBoxSizer6->Add(m_spinPeriodSeasonal, 0, wxALL|wxEXPAND, 5);
111+
m_sizerBools->Add(StaticBoxSizer6, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
98112
BoxSizer1->Add(m_sizerBools, 0, wxEXPAND, 5);
99113
BoxSizer3 = new wxBoxSizer(wxVERTICAL);
100114
Button1 = new wxButton(this, wxID_CANCEL, _T("Cancel"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("wxID_CANCEL"));
@@ -115,6 +129,8 @@ DialogTS::DialogTS(wxWindow* parent,wxWindowID id)
115129
Connect(ID_CHOICE1,wxEVT_COMMAND_CHOICE_SELECTED,(wxObjectEventFunction)&DialogTS::OnTS);
116130
Connect(ID_CHOICE2,wxEVT_COMMAND_CHOICE_SELECTED,(wxObjectEventFunction)&DialogTS::OnTS);
117131
Connect(ID_CHECKBOX12,wxEVT_COMMAND_CHECKBOX_CLICKED,(wxObjectEventFunction)&DialogTS::OnTS);
132+
Connect(ID_SPINCTRL1,wxEVT_COMMAND_SPINCTRL_UPDATED,(wxObjectEventFunction)&DialogTS::Onm_spinChange);
133+
Connect(ID_SPINCTRL2,wxEVT_COMMAND_SPINCTRL_UPDATED,(wxObjectEventFunction)&DialogTS::Onm_spinChange);
118134
//*)
119135

120136
try {

src/wxConfQT/src/DialogTS.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef DIALOGTS_H
22
#define DIALOGTS_H
33

4-
//#include <Maps/MapSpin.hpp>
4+
#include <Maps/MapSpin.hpp>
55
#include <Maps/MapCheckbox.hpp>
66
#include <Maps/MapChoiceEnum.hpp>
77
#include <MyChoiceEnum.h>
@@ -18,6 +18,8 @@
1818
//*)
1919
#endif
2020
//(*Headers(DialogTS)
21+
class wxSpinCtrl;
22+
class wxSpinEvent;
2123
//*)
2224
#include <ConfigTS.h>
2325

@@ -43,6 +45,8 @@ class DialogTS : public wxDialog
4345
wxButton* m_butScriptTextOpenR;
4446
wxButton* m_butScriptTextR;
4547
wxCheckBox* m_chkTechs;
48+
wxSpinCtrl* m_spinLagACF;
49+
wxSpinCtrl* m_spinPeriodSeasonal;
4650
wxTextCtrl* m_txtScriptPath;
4751
wxTextCtrl* m_txtScriptPathGen;
4852
wxTextCtrl* m_txtScriptPathR;
@@ -65,6 +69,8 @@ class DialogTS : public wxDialog
6569
static const long ID_CHOICE1;
6670
static const long ID_CHOICE2;
6771
static const long ID_CHECKBOX12;
72+
static const long ID_SPINCTRL1;
73+
static const long ID_SPINCTRL2;
6874
//*)
6975

7076
private:
@@ -80,10 +86,11 @@ class DialogTS : public wxDialog
8086
void Onm_butScriptTextOpenRClick(wxCommandEvent& event);
8187
void Onm_butScriptTextOpenGenClick(wxCommandEvent& event);
8288
void Onm_butScriptTextGenClick(wxCommandEvent& event);
89+
void Onm_spinChange(wxSpinEvent& event);
8390
//*)
84-
MapCheckbox m_mapCheckbox;
85-
MapChoiceEnum m_mapChoice;
86-
//MapSpin m_mapSpin;
91+
MapCheckbox m_mapCheckbox;
92+
MapChoiceEnum m_mapChoice;
93+
MapSpin m_mapSpin;
8794
std::vector<IMapControl *> m_maps;
8895

8996

src/wxConfQT/src/DialogTSImpl.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ void DialogTS::OnTS(wxCommandEvent& event)
1515
m_confTS.Write(); // OK not needed
1616
}
1717

18+
void DialogTS::Onm_spinChange(wxSpinEvent& event)
19+
{
20+
ReadSelections();
21+
m_confTS.Write(); // OK not needed
22+
}
23+
1824
void DialogTS::Init()
1925
{
2026
/*
@@ -27,8 +33,12 @@ void DialogTS::Init()
2733
m_mapChoice.Register(&m_confTS.PRED_TYPE, m_choicePredType);
2834
m_mapChoice.Register(&m_confTS.PRICE_TYPE, m_choiceSeriesType);
2935

36+
m_mapSpin.Register(&m_confTS.PLOT_LAGS_NUM, m_spinLagACF);
37+
m_mapSpin.Register(&m_confTS.PLOT_PERIOD_NUM, m_spinPeriodSeasonal);
38+
3039
m_maps.push_back(&m_mapChoice);
3140
m_maps.push_back(&m_mapCheckbox);
41+
m_maps.push_back(&m_mapSpin);
3242
}
3343

3444
/// Store to config classes

0 commit comments

Comments
 (0)