1function writeSeriesForGraph(o, fid, xrange, series_num)
2%function writeSeriesForGraph(o, fid, xrange, series_num)
3% Print a TikZ line
4%
5% INPUTS
6%   o          [report_series]    series object
7%   xrange     [dates]            range of x values for line
8%   series_num [int]              the number of this series in the total number of series passed to this graph
9%
10% OUTPUTS
11%   NONE
12%
13% SPECIAL REQUIREMENTS
14%   none
15
16% Copyright (C) 2014-2019 Dynare Team
17%
18% This file is part of Dynare.
19%
20% Dynare is free software: you can redistribute it and/or modify
21% it under the terms of the GNU General Public License as published by
22% the Free Software Foundation, either version 3 of the License, or
23% (at your option) any later version.
24%
25% Dynare is distributed in the hope that it will be useful,
26% but WITHOUT ANY WARRANTY; without even the implied warranty of
27% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28% GNU General Public License for more details.
29%
30% You should have received a copy of the GNU General Public License
31% along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
32
33%% Validate options provided by user
34if isempty(o.graphVline) && isempty(o.graphHline)
35    assert(~isempty(o.data) && isdseries(o.data), ['@report_series.writeSeriesForGraph: must ' ...
36                        'provide data as a dseries']);
37end
38
39assert(ischar(o.graphMiscTikzAddPlotOptions), ['@report_series.writeSeriesForGraph: ' ...
40                    'graphMiscTikzAddPlotOptions file must be a string']);
41assert(islogical(o.graphShowInLegend), ['@report_series.writeSeriesForGraph: ' ...
42                    'graphShowInLegend must be either true or false']);
43
44% Line
45assert(ischar(o.graphLineColor), '@report_series.writeSeriesForGraph: graphLineColor must be a string');
46assert(ischar(o.graphLineStyle), '@report_series.writeSeriesForGraph: graphLineStyle must be a string');
47assert(isfloat(o.graphLineWidth) && o.graphLineWidth > 0, ...
48       '@report_series.writeSeriesForGraph: graphLineWidth must be a positive number');
49
50% Bar
51assert(islogical(o.graphBar), '@report_series.writeSeriesForGraph: graphBar must be either true or false');
52assert(ischar(o.graphBarColor), '@report_series.writeSeriesForGraph: graphBarColor must be a string');
53assert(ischar(o.graphBarFillColor), '@report_series.writeSeriesForGraph: graphBarFillColor must be a string');
54assert(isfloat(o.graphBarWidth) && o.graphBarWidth > 0, ...
55       '@report_series.writeSeriesForGraph: graphbarWidth must be a positive number');
56
57% GraphMarker
58valid_graphMarker = {'x', '+', '-', '|', 'o', 'asterisk', 'star', '10-pointed star', 'oplus', ...
59                    'oplus*', 'otimes', 'otimes*', 'square', 'square*', 'triangle', 'triangle*', 'diamond', ...
60                    'diamond*', 'halfdiamond*', 'halfsquare*', 'halfsquare right*', ...
61                    'halfsquare left*','Mercedes star','Mercedes star flipped','halfcircle',...
62                    'halfcircle*','pentagon','pentagon star'};
63assert(isempty(o.graphMarker) || any(strcmp(o.graphMarker, valid_graphMarker)), ...
64       ['@report_series.writeSeriesForGraph: graphMarker must be one of ' addCommasToCellStr(valid_graphMarker)]);
65
66assert(ischar(o.graphMarkerEdgeColor), '@report_series.writeSeriesForGraph: graphMarkerEdgeColor must be a string');
67assert(ischar(o.graphMarkerFaceColor), '@report_series.writeSeriesForGraph: graphMarkerFaceColor must be a string');
68assert(isfloat(o.graphMarkerSize) && o.graphMarkerSize > 0, ...
69       '@report_series.writeSeriesForGraph: graphMarkerSize must be a positive number');
70
71% Marker & Line
72assert(~(strcmp(o.graphLineStyle, 'none') && isempty(o.graphMarker)), ['@report_series.writeSeriesForGraph: ' ...
73                    'you must provide at least one of graphLineStyle and graphMarker']);
74
75% Validate graphVline
76assert(isempty(o.graphVline) || (isdates(o.graphVline) && o.graphVline.ndat == 1), ...
77       '@report_series.writeSeriesForGraph: graphVline must be a dates of size one');
78assert(isempty(o.graphHline) || isnumeric(o.graphHline), ...
79       '@report_series.writeSeriesForGraph: graphHline must a single numeric value');
80
81% Zero tolerance
82assert(isfloat(o.zeroTol), '@report_series.write: zeroTol must be a float');
83
84% Fan Chart
85assert(ischar(o.graphFanShadeColor), '@report_series.writeSeriesForGraph: graphFanShadeColor must be a string');
86assert(isint(o.graphFanShadeOpacity), '@report_series.writeSeriesForGraph: graphFanShadeOpacity must be an int');
87
88%% graphVline && graphHline
89if ~isempty(o.graphVline)
90    fprintf(fid, '%%Vertical Line\n\\begin{pgfonlayer}{axis lines}\n\\draw');
91    writeLineOptions(o, fid, series_num);
92    stringsdd = strings(xrange);
93    x = find(strcmpi(date2string(o.graphVline), stringsdd));
94    fprintf(fid, ['(axis cs:%d,\\pgfkeysvalueof{/pgfplots/ymin}) -- (axis ' ...
95                  'cs:%d,\\pgfkeysvalueof{/pgfplots/ymax});\n\\end{pgfonlayer}\n'], ...
96            x, x);
97end
98if ~isempty(o.graphHline)
99    fprintf(fid, '%%Horizontal Line\n\\begin{pgfonlayer}{axis lines}\n\\addplot');
100    writeLineOptions(o, fid, series_num);
101    fprintf(fid, ['coordinates {(\\pgfkeysvalueof{/pgfplots/xmin},%f)' ...
102                  '(\\pgfkeysvalueof{/pgfplots/xmax},%f)};\n\\end{pgfonlayer}\n'], ...
103            o.graphHline, o.graphHline);
104end
105if ~isempty(o.graphVline) || ~isempty(o.graphHline)
106    % return since the code below assumes that o.data exists
107    return
108end
109
110%%
111if isempty(xrange) || all(xrange == o.data.dates)
112    ds = o.data;
113else
114    ds = o.data(xrange);
115end
116
117thedata = setDataToZeroFromZeroTol(o, ds);
118fprintf(fid, '%%series %s\n\\addplot', o.data.name{:});
119writeLineOptions(o, fid, series_num);
120fprintf(fid,'\ntable[row sep=crcr]{\nx y\\\\\n');
121for i=1:ds.dates.ndat
122    if ~isnan(thedata(i))
123        fprintf(fid, '%d %f\\\\\n', i, thedata(i));
124    end
125end
126fprintf(fid,'};\n');
127
128% For Fan charts
129if ispc || ismac
130    if ~isempty(o.graphFanShadeColor)
131        assert(isint(series_num) && series_num > 1, ['@report_series.writeSeriesForGraph: can only add '...
132                            'graphFanShadeColor and graphFanShadeOpacity starting from the ' ...
133                            'second series in the graph']);
134        fprintf(fid, '\\addplot[%s!%d, forget plot] fill between[of=%d and %d];\n', ...
135                o.graphFanShadeColor, o.graphFanShadeOpacity, series_num, series_num - 1);
136    end
137end
138end
139
140function writeLineOptions(o, fid, series_num)
141if o.graphBar
142    fprintf(fid, '[ybar,ybar legend,color=%s,fill=%s,line width=%fpt',...
143            o.graphBarColor, o.graphBarFillColor, o.graphBarWidth);
144else
145    fprintf(fid, '[color=%s,%s,line width=%fpt,line join=round',...
146            o.graphLineColor, o.graphLineStyle, o.graphLineWidth);
147
148    if ~isempty(o.graphMarker)
149        if isempty(o.graphMarkerEdgeColor)
150            o.graphMarkerEdgeColor = o.graphLineColor;
151        end
152        if isempty(o.graphMarkerFaceColor)
153            o.graphMarkerFaceColor = o.graphLineColor;
154        end
155        fprintf(fid, ',mark=%s,mark size=%f,every mark/.append style={draw=%s,fill=%s}',...
156                o.graphMarker,o.graphMarkerSize,o.graphMarkerEdgeColor,o.graphMarkerFaceColor);
157    end
158end
159if ~isempty(o.graphMiscTikzAddPlotOptions)
160    fprintf(fid, ',%s', o.graphMiscTikzAddPlotOptions);
161end
162if isunix && ~ismac
163    fprintf(fid,']');
164else
165    fprintf(fid,',name path=%d]', series_num);
166end
167end
168