Commit e19f03b4 authored by Houtan Bastani's avatar Houtan Bastani

replace reporting code with submodule. closes #811

parent 2809afaa
......@@ -21,3 +21,6 @@
path = matlab/modules/dseries
url = https://github.com/DynareTeam/dseries.git
branch = old-oop-style
[submodule "matlab/modules/reporting"]
path = matlab/modules/reporting
url = https://github.com/DynareTeam/reporting.git
......@@ -66,7 +66,7 @@ addpath([dynareroot '/utilities/doc/'])
addpath([dynareroot '/utilities/tests/src/'])
addpath([dynareroot '/utilities/dataset/'])
addpath([dynareroot '/utilities/general/'])
addpath([dynareroot '/reports/'])
addpath([dynareroot '/modules/reporting/src/'])
% For functions that exist only under some Octave versions
% or some MATLAB versions, and for which we provide some replacement functions
......
Subproject commit d242c92493693a8dc3b369f36b8762d8c31179fd
function o = addSeries(o, varargin)
% function o = addSeries(o, varargin)
% Copyright (C) 2013-2014 Dynare Team
%
% This file is part of Dynare.
%
% Dynare is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% Dynare is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with Dynare. If not, see <http://www.gnu.org/licenses/>.
o.series{end+1} = report_series(varargin{:});
end
\ No newline at end of file
function display(o)
%function display(o)
% Display a Graph object
%
% INPUTS
% o [graph] graph object
%
% OUTPUTS
% none
%
% SPECIAL REQUIREMENTS
% none
% Copyright (C) 2013-2014 Dynare Team
%
% This file is part of Dynare.
%
% Dynare is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% Dynare is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with Dynare. If not, see <http://www.gnu.org/licenses/>.
display_reporting_object(o);
end
\ No newline at end of file
function lastIndex = end(o, k, n)
% function lastIndex = end(o, k, n)
% End keyword
%
% INPUTS
% o [graph] graph object
% k [integer] index where end appears
% n [integer] number of indices
%
% OUTPUTS
% lastIndex [integer] last graph index
%
% SPECIAL REQUIREMENTS
% none
% Copyright (C) 2013-2014 Dynare Team
%
% This file is part of Dynare.
%
% Dynare is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% Dynare is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with Dynare. If not, see <http://www.gnu.org/licenses/>.
assert(k==1 && n==1, '@graph/end: graph only has one dimension');
lastIndex = length(o.series);
end
\ No newline at end of file
function o = graph(varargin)
%function o = graph(varargin)
% Graph Class Constructor
%
% INPUTS
% varargin 0 args : empty graph object
% 1 arg : must be graph object (return a copy of arg)
% > 1 args: option/value pairs (see structure below for
% options)
%
% OUTPUTS
% o [graph] graph object
%
% SPECIAL REQUIREMENTS
% none
% Copyright (C) 2013-2014 Dynare Team
%
% This file is part of Dynare.
%
% Dynare is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% Dynare is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with Dynare. If not, see <http://www.gnu.org/licenses/>.
o = struct;
o.series = {};
o.title = '';
o.titleFormat = '';
o.titleFontSize = 'normalsize';
o.ylabel = '';
o.xlabel = '';
o.axisShape = 'box';
o.graphDirName = 'tmpRepDir';
o.graphName = '';
o.data = '';
o.seriesToUse = '';
o.xrange = '';
o.xAxisTight = true;
o.yrange = '';
o.yAxisTight = false;
o.shade = '';
o.shadeColor = 'green';
o.shadeOpacity = 20;
o.showGrid = true;
o.showLegend = false;
o.legendAt = [];
o.showLegendBox = false;
o.legendLocation = 'south east';
o.legendOrientation = 'horizontal';
o.legendFontSize = 'tiny';
o.showZeroline = false;
o.zeroLineColor = 'black';
o.xTicks = [];
o.xTickLabels = {};
o.xTickLabelRotation = 0;
o.xTickLabelAnchor = 'east';
o.yTickLabelScaled = true;
o.yTickLabelPrecision = 0;
o.yTickLabelFixed = true;
o.yTickLabelZeroFill = true;
o.tickFontSize = 'normalsize';
o.width = 6;
o.height = 4.5;
o.miscTikzPictureOptions = '';
o.miscTikzAxisOptions = '';
o.writeCSV = false;
if nargin == 1
assert(isa(varargin{1}, 'graph'),['@graph.graph: with one arg you ' ...
'must pass a graph object']);
o = varargin{1};
return;
elseif nargin > 1
if round(nargin/2) ~= nargin/2
error(['@graph.graph: options must be supplied in name/value ' ...
'pairs.']);
end
optNames = fieldnames(o);
% overwrite default values
for pair = reshape(varargin, 2, [])
ind = find(strcmpi(optNames, pair{1}));
assert(isempty(ind) || length(ind) == 1);
if ~isempty(ind)
o.(optNames{ind}) = pair{2};
else
error('@graph.graph: %s is not a recognized option.', pair{1});
end
end
end
% Check options provided by user
if ischar(o.title)
o.title = {o.title};
end
assert(iscellstr(o.title), '@graph.graph: title must be a cell array of string(s)');
assert(ischar(o.titleFormat), '@graph.graph: titleFormat file must be a string');
assert(ischar(o.xlabel), '@graph.graph: xlabel file must be a string');
assert(ischar(o.ylabel), '@graph.graph: ylabel file must be a string');
assert(ischar(o.miscTikzPictureOptions), '@graph.graph: miscTikzPictureOptions file must be a string');
assert(ischar(o.miscTikzAxisOptions), '@graph.graph: miscTikzAxisOptions file must be a string');
assert(ischar(o.graphName), '@graph.graph: graphName must be a string');
assert(ischar(o.graphDirName), '@graph.graph: graphDirName must be a string');
assert(islogical(o.showGrid), '@graph.graph: showGrid must be either true or false');
assert(islogical(o.xAxisTight), '@graph.graph: xAxisTight must be either true or false');
assert(islogical(o.yAxisTight), '@graph.graph: yAxisTight must be either true or false');
assert(islogical(o.showLegend), '@graph.graph: showLegend must be either true or false');
assert(isempty(o.legendAt) || (isfloat(o.legendAt) && length(o.legendAt)==2), ...
'@graph.graph: legendAt must be a double array of size two');
assert(islogical(o.showLegendBox), '@graph.graph: showLegendBox must be either true or false');
assert(islogical(o.showZeroline), '@graph.graph: showZeroline must be either true or false');
assert(isfloat(o.shadeOpacity) && length(o.shadeOpacity)==1 && ...
o.shadeOpacity >= 0 && o.shadeOpacity <= 100, ...
'@graph.graph: o.shadeOpacity must be a real in [0 100]');
assert(isfloat(o.width), '@graph.graph: o.width must be a real number');
assert(isfloat(o.height), '@graph.graph: o.height must be a real number');
assert(isfloat(o.xTickLabelRotation), '@graph.graph: o.xTickLabelRotation must be a real number');
assert(ischar(o.xTickLabelAnchor), '@graph.graph: xTickLabelAnchor must be a string');
assert(isint(o.yTickLabelPrecision), '@graph.graph: o.yTickLabelPrecision must be an integer');
assert(islogical(o.yTickLabelFixed), '@graph.graph: yTickLabelFixed must be either true or false');
assert(islogical(o.yTickLabelZeroFill), '@graph.graph: yTickLabelZeroFill must be either true or false');
assert(islogical(o.yTickLabelScaled), '@graph.graph: yTickLabelScaled must be either true or false');
assert(islogical(o.writeCSV), '@graph.graph: writeCSV must be either true or false');
assert(ischar(o.shadeColor), '@graph.graph: shadeColor must be a string');
assert(ischar(o.zeroLineColor), '@graph.graph: zeroLineColor must be a string');
assert(any(strcmp(o.axisShape, {'box', 'L'})), ['@graph.graph: axisShape ' ...
'must be one of ''box'' or ''L''']);
valid_legend_locations = ...
{'south west','south east','north west','north east','outer north east'};
assert(any(strcmp(o.legendLocation, valid_legend_locations)), ...
['@graph.graph: legendLocation must be one of ' strjoin(valid_legend_locations, ' ')]);
valid_font_sizes = {'tiny', 'scriptsize', 'footnotesize', 'small', ...
'normalsize', 'large', 'Large', 'LARGE', 'huge', 'Huge'};
assert(any(strcmp(o.legendFontSize, valid_font_sizes)), ...
['@graph.graph: legendFontSize must be one of ' strjoin(valid_font_sizes)]);
assert(any(strcmp(o.titleFontSize, valid_font_sizes)), ...
['@graph.graph: titleFontSize must be one of ' strjoin(valid_font_sizes)]);
assert(any(strcmp(o.tickFontSize, valid_font_sizes)), ...
['@graph.graph: tickFontSize must be one of ' strjoin(valid_font_sizes)]);
valid_legend_orientations = {'vertical', 'horizontal'};
assert(any(strcmp(o.legendOrientation, valid_legend_orientations)), ...
['@graph.graph: legendOrientation must be one of ' strjoin(valid_legend_orientations, ' ')]);
assert(isempty(o.shade) || (isdates(o.shade) && o.shade.ndat >= 2), ...
['@graph.graph: shade is specified as a dates range, e.g. ' ...
'''dates(''1999q1''):dates(''1999q3'')''.']);
assert(isempty(o.xrange) || (isdates(o.xrange) && o.xrange.ndat >= 2), ...
['@graph.graph: xrange is specified as a dates range, e.g. ' ...
'''dates(''1999q1''):dates(''1999q3'')''.']);
assert(isempty(o.yrange) || (isfloat(o.yrange) && length(o.yrange) == 2 && ...
o.yrange(1) < o.yrange(2)), ...
['@graph.graph: yrange is specified an array with two float entries, ' ...
'the lower bound and upper bound.']);
assert(isempty(o.data) || isdseries(o.data), ['@graph.graph: data must ' ...
'be a dseries']);
assert(isempty(o.seriesToUse) || iscellstr(o.seriesToUse), ['@graph.graph: ' ...
'seriesToUse must be a cell array of string(s)']);
assert(isempty(o.xTicks) || isfloat(o.xTicks),...
'@graph.graph: xTicks must be a numerical array');
assert(iscellstr(o.xTickLabels) || (ischar(o.xTickLabels) && strcmpi(o.xTickLabels, 'ALL')), ...
['@graph.graph: xTickLabels must be a cell array of strings or ' ...
'equivalent to the string ''ALL''']);
if ~isempty(o.xTickLabels)
assert((ischar(o.xTickLabels) && strcmpi(o.xTickLabels, 'ALL')) || ...
~isempty(o.xTicks), ['@graph.graph: if you set xTickLabels and ' ...
'it''s not equal to ''ALL'', you must set xTicks']);
end
if ~isempty(o.xTicks)
assert(~isempty(o.xTickLabels), '@graph.graph: if you set xTicks, you must set xTickLabels');
end
% using o.seriesToUse, create series objects and put them in o.series
if ~isempty(o.data)
if isempty(o.seriesToUse)
for i=1:o.data.vobs
o.series{end+1} = report_series('data', o.data{o.data.name{i}});
end
else
for i=1:length(o.seriesToUse)
o.series{end+1} = report_series('data', o.data{o.seriesToUse{i}});
end
end
end
o = rmfield(o, 'seriesToUse');
o = rmfield(o, 'data');
if ~exist(o.graphDirName, 'file')
mkdir(o.graphDirName);
end
% Create graph object
o = class(o, 'graph');
end
\ No newline at end of file
function B = subsasgn(A, S, V)
% function B = subsasgn(A, S, V)
% Copyright (C) 2013-2014 Dynare Team
%
% This file is part of Dynare.
%
% Dynare is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% Dynare is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with Dynare. If not, see <http://www.gnu.org/licenses/>.
B = A;
if length(S) > 1
for i=1:(length(S)-1)
B = subsref(B, S(i));
end
B = subsasgn(B, S(end), V);
B = subsasgn(A, S(1:(end-1)), B);
return
end
switch S.type
case '()'
index = S.subs{:};
assert(isnumeric(index));
B.series{index} = V;
case '.'
switch S.subs
case fieldnames(A)
B.(S.subs) = V;
otherwise
error(['@graph.subsasgn: field ' S.subs 'does not exist']);
end
case '{}'
assert(isint(S.subs{1}));
B{S.subs{1}} = V;
otherwise
error('@graph.subsasgn: syntax error');
end
end
\ No newline at end of file
function A = subsref(A, S)
%function A = subsref(A, S)
% Copyright (C) 2013-2014 Dynare Team
%
% This file is part of Dynare.
%
% Dynare is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% Dynare is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with Dynare. If not, see <http://www.gnu.org/licenses/>.
switch S(1).type
case '.'
switch S(1).subs
case fieldnames(A)
A = A.(S(1).subs);
case methods(A)
if areParensNext(S)
A = feval(S(1).subs, A, S(2).subs{:});
S = shiftS(S,1);
else
A = feval(S(1).subs, A);
end
otherwise
error(['@graph.subsref: unknown field or method: ' S(1).subs]);
end
case '()'
if isempty(S(1).subs{:})
A = A.series;
else
assert(isnumeric(S(1).subs{:}));
A = A.series{S(1).subs{:}};
end
case '{}'
A = A.series{S(1).subs{:}};
otherwise
error('@graph.subsref: impossible case')
end
S = shiftS(S,1);
if length(S) >= 1
A = subsref(A, S);
end
end
function o = write(o, fid, pg, sec, row, col)
%function o = write(o, fid, pg, sec, row, col)
% Write a Graph object
%
% INPUTS
% o [graph] graph object
% fid [integer] file id
% pg [integer] this page number
% sec [integer] this section number
% row [integer] this row number
% col [integer] this col number
%
% OUTPUTS
% o [graph] graph object
%
% SPECIAL REQUIREMENTS
% none
% Copyright (C) 2013-2014 Dynare Team
%
% This file is part of Dynare.
%
% Dynare is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% Dynare is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with Dynare. If not, see <http://www.gnu.org/licenses/>.
assert(fid ~= -1);
o = writeGraphFile(o, pg, sec, row, col);
fprintf(fid, '\\input{%s}', o.graphName);
end
\ No newline at end of file
function o = writeGraphFile(o, pg, sec, row, col)
%function o = writeGraphFile(o, pg, sec, row, col)
% Write the tikz file that contains the graph
%
% INPUTS
% o [graph] graph object
% pg [integer] this page number
% sec [integer] this section number
% row [integer] this row number
% col [integer] this col number
%
% OUTPUTS
% o [graph] graph object
%
% SPECIAL REQUIREMENTS
% none
% Copyright (C) 2013-2014 Dynare Team
%
% This file is part of Dynare.
%
% Dynare is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% Dynare is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with Dynare. If not, see <http://www.gnu.org/licenses/>.
ne = length(o.series);
if ne < 1
warning('@graph.writeGraphFile: no series to plot, returning');
return;
end
if isempty(o.graphName)
o.graphName = sprintf('%s/graph_pg%d_sec%d_row%d_col%d.tex', o.graphDirName, pg, sec, row, col);
else
o.graphName = [o.graphDirName '/' o.graphName];
end
[fid, msg] = fopen(o.graphName, 'w');
if fid == -1
error(['@graph.writeGraphFile: ' msg]);
end
fprintf(fid, '\\begin{tikzpicture}[baseline');
if ~isempty(o.miscTikzPictureOptions)
fprintf(fid, ',%s', o.miscTikzPictureOptions);
end
fprintf(fid, ']');
if isempty(o.xrange)
dd = getMaxRange(o.series);
else
dd = o.xrange;
end
fprintf(fid, '\\begin{axis}[%%\n');
% set tick labels
if isempty(o.xTickLabels)
stringsdd = strings(dd);
if ~isempty(o.shade)
x1 = find(strcmpi(date2string(o.shade(1)), stringsdd));
x2 = find(strcmpi(date2string(o.shade(end)), stringsdd));
if x1 == 1
x = [1 x2 dd.ndat];
xTickLabels = [stringsdd(1) stringsdd(x2) stringsdd(end)];
elseif x2 == dd.ndat
x = [1 x1 dd.ndat];
xTickLabels = [stringsdd(1) stringsdd(x1) stringsdd(end)];
else
x = [1 x1 x2 dd.ndat];
xTickLabels = [stringsdd(1) stringsdd(x1) stringsdd(x2) stringsdd(end)];
end
else
x = [1 dd.ndat];
xTickLabels = [stringsdd(1) stringsdd(end)];
end
fprintf(fid, 'xminorticks=true,\nyminorticks=true,\n');
elseif iscell(o.xTickLabels)
fprintf(fid,'minor xtick,\n');
x = o.xTicks;
xTickLabels = o.xTickLabels;
else
x = [1:dd.ndat];
xTickLabels = strings(dd);
end
fprintf(fid, 'xticklabels={');
xlen = length(x);
for i = 1:xlen
fprintf(fid,'%s,',lower(xTickLabels{i}));
end
fprintf(fid, '},\nxtick={');
for i = 1:xlen
fprintf(fid, '%d',x(i));
if i ~= length(x)
fprintf(fid,',');
end
end
fprintf(fid, '},\ny tick label style={\n/pgf/number format/.cd,\n');
if o.yTickLabelFixed
fprintf(fid, 'fixed,\n');
end
if o.yTickLabelZeroFill
fprintf(fid, 'zerofill,\n');
end
fprintf(fid, 'precision=%d,\n/tikz/.cd\n},\n', o.yTickLabelPrecision);
fprintf(fid, 'x tick label style={rotate=%f', o.xTickLabelRotation);
if o.xTickLabelRotation ~= 0
fprintf(fid, ',anchor=%s', o.xTickLabelAnchor);
end
fprintf(fid, ['},\n',...
'width=%fin,\n'...
'height=%fin,\n'...
'scale only axis,\n'...
'unbounded coords=jump,\n'], o.width, o.height);
if strcmpi(o.axisShape, 'box')
fprintf(fid, 'axis lines=box,\n');
elseif strcmpi(o.axisShape, 'L')
fprintf(fid, 'axis x line=bottom,\naxis y line=left,\n');
end
if ~isempty(o.title{1})
fprintf(fid, 'title style={align=center');
if ~isempty(o.titleFormat)
fprintf(fid, ',font=%s', o.titleFormat);
end
fprintf(fid, '},\ntitle=');
nt = length(o.title);
for i=1:nt
fprintf(fid, '%s', o.title{i});
if i ~= nt
fprintf(fid, '\\\\');
end
end
fprintf(fid, ',\n');
end
if o.xAxisTight
fprintf(fid, 'enlarge x limits=false,\n');
else
fprintf(fid, 'enlarge x limits=true,\n');
end
if isempty(o.yrange)
if o.yAxisTight
fprintf(fid, 'enlarge y limits=false,\n');
else
fprintf(fid, 'enlarge y limits=true,\n');
end
else
fprintf(fid, 'ymin=%f,\nymax=%f,\n',o.yrange(1),o.yrange(2));
end
fprintf(fid, 'xmin = 1,\nxmax = %d,\n', length(dd));
if o.showLegend
fprintf(fid, 'legend style={');
if ~o.showLegendBox
fprintf(fid, 'draw=none,');
end
fprintf(fid, 'font=\\%s,', o.legendFontSize);
if strcmp(o.legendOrientation, 'horizontal')
fprintf(fid,'legend columns=-1,');
end
if isempty(o.legendAt)
fprintf(fid, '},\nlegend pos=%s,\n', o.legendLocation);
else
fprintf(fid, 'at={(%f,%f)}},\n',o.legendAt(1),o.legendAt(2));
end
end
fprintf(fid, 'tick label style={font=\\%s},\n', o.tickFontSize);
if o.showGrid
fprintf(fid, 'xmajorgrids=true,\nymajorgrids=true,\n');
end
if ~isempty(o.xlabel)
fprintf(fid, 'xlabel=%s,\n', o.xlabel);
end
if ~isempty(o.ylabel)
fprintf(fid, 'ylabel=%s,\n', o.ylabel);
end
if ~o.yTickLabelScaled
fprintf(fid, 'scaled y ticks = false,\n');
end
if ~isempty(o.miscTikzAxisOptions)
fprintf(fid, '%s', o.miscTikzAxisOptions);
end
fprintf(fid, ']\n');
if ~isempty(o.title{1})
fprintf(fid, '\\pgfplotsset{every axis title/.append style={}}=[font=\\%s]\n', o.titleFontSize);
end
if ~isempty(o.shade)
fprintf(fid, '%%shading\n');
stringsdd = strings(dd);
x1 = find(strcmpi(date2string(o.shade(1)), stringsdd));