788 |
13 Apr 09 |
jari |
// $Id$ |
788 |
13 Apr 09 |
jari |
2 |
|
788 |
13 Apr 09 |
jari |
3 |
/* |
1267 |
02 Nov 10 |
peter |
Copyright (C) 2009, 2010 Jari Häkkinen, Peter Johansson |
1635 |
30 Mar 23 |
peter |
Copyright (C) 2011, 2023 Peter Johansson |
788 |
13 Apr 09 |
jari |
6 |
|
788 |
13 Apr 09 |
jari |
This file is part of svndigest, http://dev.thep.lu.se/svndigest |
788 |
13 Apr 09 |
jari |
8 |
|
788 |
13 Apr 09 |
jari |
svndigest is free software; you can redistribute it and/or modify it |
788 |
13 Apr 09 |
jari |
under the terms of the GNU General Public License as published by |
788 |
13 Apr 09 |
jari |
the Free Software Foundation; either version 3 of the License, or |
788 |
13 Apr 09 |
jari |
(at your option) any later version. |
788 |
13 Apr 09 |
jari |
13 |
|
788 |
13 Apr 09 |
jari |
svndigest is distributed in the hope that it will be useful, but |
788 |
13 Apr 09 |
jari |
WITHOUT ANY WARRANTY; without even the implied warranty of |
788 |
13 Apr 09 |
jari |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
788 |
13 Apr 09 |
jari |
General Public License for more details. |
788 |
13 Apr 09 |
jari |
18 |
|
788 |
13 Apr 09 |
jari |
You should have received a copy of the GNU General Public License |
788 |
13 Apr 09 |
jari |
along with svndigest. If not, see <http://www.gnu.org/licenses/>. |
788 |
13 Apr 09 |
jari |
21 |
*/ |
788 |
13 Apr 09 |
jari |
22 |
|
1619 |
12 Mar 23 |
peter |
23 |
#include <config.h> |
1619 |
12 Mar 23 |
peter |
24 |
|
788 |
13 Apr 09 |
jari |
25 |
#include "Graph.h" |
788 |
13 Apr 09 |
jari |
26 |
|
875 |
23 Nov 09 |
jari |
27 |
#include "Date.h" |
875 |
23 Nov 09 |
jari |
28 |
|
885 |
24 Nov 09 |
jari |
29 |
#include <algorithm> |
1255 |
01 Nov 10 |
peter |
30 |
#include <cassert> |
872 |
22 Nov 09 |
jari |
31 |
#include <cmath> |
883 |
24 Nov 09 |
jari |
32 |
#include <sstream> |
872 |
22 Nov 09 |
jari |
33 |
|
788 |
13 Apr 09 |
jari |
34 |
namespace theplu { |
788 |
13 Apr 09 |
jari |
35 |
namespace svndigest { |
788 |
13 Apr 09 |
jari |
36 |
|
1280 |
06 Nov 10 |
peter |
37 |
svn_revnum_t Graph::rev_max_=0; |
1255 |
01 Nov 10 |
peter |
38 |
svn_revnum_t Graph::rev_min_=0; |
1330 |
27 Jan 11 |
peter |
39 |
std::vector<time_t> Graph::dates_; |
855 |
19 Nov 09 |
jari |
40 |
|
1614 |
15 Feb 23 |
peter |
41 |
Graph::Graph(const std::string& filename, const std::string& format, |
1614 |
15 Feb 23 |
peter |
42 |
const std::string& title) |
902 |
27 Nov 09 |
peter |
43 |
#ifdef HAVE_PLPLOT |
1327 |
27 Jan 11 |
peter |
44 |
: plots_(0), pls_(1,1,format.c_str(),filename.c_str()), |
1614 |
15 Feb 23 |
peter |
45 |
title_(title), xmin_(0.0), xmax_(0.0), ymin_(0.0), ymax_(0.0) |
788 |
13 Apr 09 |
jari |
46 |
{ |
949 |
04 Dec 09 |
jari |
// should match the maximum number of authors plotted, change this |
949 |
04 Dec 09 |
jari |
// when the maximum number of authors becomes configurable |
949 |
04 Dec 09 |
jari |
49 |
legend_.reserve(10); |
929 |
02 Dec 09 |
jari |
// we use color map 0 position 0 for background color |
1182 |
25 Aug 10 |
peter |
51 |
pls_.scolbga(255,255,255,0); |
1126 |
08 Jul 10 |
peter |
52 |
pls_.setopt("geometry", "600x500"); |
855 |
19 Nov 09 |
jari |
53 |
pls_.init(); |
855 |
19 Nov 09 |
jari |
54 |
pls_.adv(0); |
855 |
19 Nov 09 |
jari |
55 |
pls_.vsta(); |
950 |
04 Dec 09 |
jari |
56 |
pls_.syax(6,0); |
788 |
13 Apr 09 |
jari |
57 |
} |
902 |
27 Nov 09 |
peter |
58 |
#else |
902 |
27 Nov 09 |
peter |
59 |
{} |
902 |
27 Nov 09 |
peter |
60 |
#endif |
788 |
13 Apr 09 |
jari |
61 |
|
859 |
19 Nov 09 |
jari |
62 |
|
855 |
19 Nov 09 |
jari |
63 |
Graph::~Graph(void) |
855 |
19 Nov 09 |
jari |
64 |
{ |
883 |
24 Nov 09 |
jari |
65 |
print_legend(); |
855 |
19 Nov 09 |
jari |
66 |
} |
855 |
19 Nov 09 |
jari |
67 |
|
859 |
19 Nov 09 |
jari |
68 |
|
855 |
19 Nov 09 |
jari |
69 |
bool Graph::date_xticks(void) |
855 |
19 Nov 09 |
jari |
70 |
{ |
1330 |
27 Jan 11 |
peter |
71 |
return dates_.size() != 0; |
855 |
19 Nov 09 |
jari |
72 |
} |
855 |
19 Nov 09 |
jari |
73 |
|
855 |
19 Nov 09 |
jari |
74 |
|
929 |
02 Dec 09 |
jari |
75 |
void Graph::current_color(const legend_data& legend) |
883 |
24 Nov 09 |
jari |
76 |
{ |
929 |
02 Dec 09 |
jari |
// we use color map 0 position 1 for current color |
902 |
27 Nov 09 |
peter |
78 |
#ifdef HAVE_PLPLOT |
883 |
24 Nov 09 |
jari |
79 |
pls_.scol0a(1,legend.r,legend.g,legend.b,1.0); |
902 |
27 Nov 09 |
peter |
80 |
#endif |
883 |
24 Nov 09 |
jari |
81 |
} |
883 |
24 Nov 09 |
jari |
82 |
|
883 |
24 Nov 09 |
jari |
83 |
|
929 |
02 Dec 09 |
jari |
84 |
void Graph::current_color(unsigned char r, unsigned char g, unsigned char b) |
859 |
19 Nov 09 |
jari |
85 |
{ |
929 |
02 Dec 09 |
jari |
// we use color map 0 position 1 for current color |
902 |
27 Nov 09 |
peter |
87 |
#ifdef HAVE_PLPLOT |
863 |
20 Nov 09 |
jari |
88 |
pls_.scol0a(1,r,g,b,1.0); |
902 |
27 Nov 09 |
peter |
89 |
#endif |
859 |
19 Nov 09 |
jari |
90 |
} |
859 |
19 Nov 09 |
jari |
91 |
|
859 |
19 Nov 09 |
jari |
92 |
|
1194 |
03 Oct 10 |
peter |
93 |
void Graph::plot(const SumVector& y, const std::string& label, |
883 |
24 Nov 09 |
jari |
94 |
unsigned int lines) |
855 |
19 Nov 09 |
jari |
95 |
{ |
902 |
27 Nov 09 |
peter |
96 |
#ifdef HAVE_PLPLOT |
883 |
24 Nov 09 |
jari |
97 |
if (!plots_) { |
1418 |
25 Oct 11 |
peter |
98 |
assert(!date_xticks() || static_cast<size_t>(rev_min_)<dates_.size()); |
1330 |
27 Jan 11 |
peter |
99 |
assert(!date_xticks() || dates_[rev_min_]); |
1418 |
25 Oct 11 |
peter |
100 |
assert(static_cast<size_t>(rev_min_)<dates_.size() || !date_xticks()); |
1330 |
27 Jan 11 |
peter |
101 |
xmin_= date_xticks() ? dates_[rev_min_] : rev_min_; |
1418 |
25 Oct 11 |
peter |
102 |
assert(static_cast<size_t>(rev_max_)<dates_.size() || !date_xticks()); |
1330 |
27 Jan 11 |
peter |
103 |
xmax_= date_xticks() ? dates_[rev_max_] : rev_max_; |
883 |
24 Nov 09 |
jari |
104 |
xrange_=xmax_-xmin_; |
883 |
24 Nov 09 |
jari |
105 |
yrange_=ymax_-ymin_; |
883 |
24 Nov 09 |
jari |
106 |
pls_.wind(xmin_, xmax_, ymin_, ymax_); |
875 |
23 Nov 09 |
jari |
107 |
|
863 |
20 Nov 09 |
jari |
// draw plot frame, x and y ticks only for the first plot |
863 |
20 Nov 09 |
jari |
109 |
pls_.scol0a(2,0,0,0,1.0); |
863 |
20 Nov 09 |
jari |
110 |
pls_.col0(2); |
875 |
23 Nov 09 |
jari |
111 |
|
886 |
24 Nov 09 |
jari |
112 |
std::string xopt("bcnstv"); |
886 |
24 Nov 09 |
jari |
113 |
if (date_xticks()) { |
1622 |
12 Mar 23 |
peter |
114 |
xopt="bcn"; |
886 |
24 Nov 09 |
jari |
115 |
} |
875 |
23 Nov 09 |
jari |
116 |
|
1327 |
27 Jan 11 |
peter |
117 |
pls_.box(xopt.c_str(), 0, 1, "bcnstv", 0, 2); |
875 |
23 Nov 09 |
jari |
118 |
pls_.lab("Date", "Number of lines", title_.c_str()); |
1622 |
12 Mar 23 |
peter |
119 |
|
1622 |
12 Mar 23 |
peter |
120 |
PLFLT xrange = (xmax_ - xmin_); |
1622 |
12 Mar 23 |
peter |
121 |
PLFLT secs_per_year = 3600 * 24 * 365.25; |
1622 |
12 Mar 23 |
peter |
122 |
PLFLT year_range = xrange / secs_per_year; |
1622 |
12 Mar 23 |
peter |
123 |
int year_step; |
1622 |
12 Mar 23 |
peter |
124 |
if (year_range < 8) |
1622 |
12 Mar 23 |
peter |
125 |
year_step = 1; |
1622 |
12 Mar 23 |
peter |
126 |
else if (year_range < 20) |
1622 |
12 Mar 23 |
peter |
127 |
year_step = 2; |
1622 |
12 Mar 23 |
peter |
128 |
else |
1622 |
12 Mar 23 |
peter |
129 |
year_step = 5; |
1622 |
12 Mar 23 |
peter |
130 |
|
1622 |
12 Mar 23 |
peter |
131 |
PLFLT year_min = |
1622 |
12 Mar 23 |
peter |
132 |
floor(xmin_ / (year_step * secs_per_year)) * year_step; |
1622 |
12 Mar 23 |
peter |
133 |
PLFLT year_max = |
1622 |
12 Mar 23 |
peter |
134 |
ceil(xmax_ / (year_step * secs_per_year)) * year_step; |
1622 |
12 Mar 23 |
peter |
135 |
|
1622 |
12 Mar 23 |
peter |
136 |
const double xtic_size = 0.02 * ymax_; |
1622 |
12 Mar 23 |
peter |
137 |
for (int year = year_min; year<year_max; year+=year_step) { |
1622 |
12 Mar 23 |
peter |
138 |
PLFLT x = year * secs_per_year; |
1622 |
12 Mar 23 |
peter |
139 |
if (x >= xmin_ && x <= xmax_) { |
1622 |
12 Mar 23 |
peter |
140 |
pls_.join(x, 0, x, xtic_size); |
1622 |
12 Mar 23 |
peter |
141 |
std::ostringstream ss; |
1622 |
12 Mar 23 |
peter |
142 |
ss << (1970+year); |
1622 |
12 Mar 23 |
peter |
143 |
pls_.mtex("b", 1.7, (x-xmin_)/xrange, 0.5, ss.str().c_str()); |
1622 |
12 Mar 23 |
peter |
144 |
} |
1622 |
12 Mar 23 |
peter |
145 |
} |
1622 |
12 Mar 23 |
peter |
146 |
|
1622 |
12 Mar 23 |
peter |
147 |
for (int year = year_min; year<year_max; ++year) { |
1622 |
12 Mar 23 |
peter |
148 |
if (year % year_step) { |
1622 |
12 Mar 23 |
peter |
149 |
PLFLT x = year * secs_per_year; |
1622 |
12 Mar 23 |
peter |
150 |
if (x >= xmin_ && x <= xmax_) { |
1622 |
12 Mar 23 |
peter |
151 |
pls_.join(x, 0, x, 0.5*xtic_size); |
1622 |
12 Mar 23 |
peter |
152 |
} |
1622 |
12 Mar 23 |
peter |
153 |
} |
1622 |
12 Mar 23 |
peter |
154 |
} |
1622 |
12 Mar 23 |
peter |
155 |
|
863 |
20 Nov 09 |
jari |
156 |
} |
863 |
20 Nov 09 |
jari |
157 |
++plots_; |
878 |
23 Nov 09 |
jari |
158 |
|
878 |
23 Nov 09 |
jari |
159 |
pls_.col0(1); |
1198 |
04 Oct 10 |
peter |
160 |
|
1198 |
04 Oct 10 |
peter |
161 |
SumVector::const_iterator iter = y.begin(); |
1255 |
01 Nov 10 |
peter |
162 |
svn_revnum_t x0=rev_min_; |
1198 |
04 Oct 10 |
peter |
163 |
PLFLT y0=0; |
1198 |
04 Oct 10 |
peter |
164 |
for (; iter!=y.end(); ++iter) { |
1198 |
04 Oct 10 |
peter |
165 |
staircase(x0, y0, iter->first, iter->second); |
1198 |
04 Oct 10 |
peter |
166 |
x0 = iter->first; |
1198 |
04 Oct 10 |
peter |
167 |
y0 = iter->second; |
855 |
19 Nov 09 |
jari |
168 |
} |
1280 |
06 Nov 10 |
peter |
169 |
staircase(x0, y0, rev_max_, y0); |
883 |
24 Nov 09 |
jari |
170 |
|
883 |
24 Nov 09 |
jari |
171 |
legend_data legend; |
883 |
24 Nov 09 |
jari |
172 |
legend.label=label; |
883 |
24 Nov 09 |
jari |
173 |
legend.lines=lines; |
883 |
24 Nov 09 |
jari |
174 |
pls_.gcol0(1,legend.r,legend.g,legend.b); |
883 |
24 Nov 09 |
jari |
175 |
legend_.push_back(legend); |
902 |
27 Nov 09 |
peter |
176 |
#endif |
855 |
19 Nov 09 |
jari |
177 |
} |
855 |
19 Nov 09 |
jari |
178 |
|
855 |
19 Nov 09 |
jari |
179 |
|
883 |
24 Nov 09 |
jari |
180 |
void Graph::print_legend(void) |
878 |
23 Nov 09 |
jari |
181 |
{ |
902 |
27 Nov 09 |
peter |
182 |
#ifdef HAVE_PLPLOT |
883 |
24 Nov 09 |
jari |
183 |
PLFLT line_length=0.05*xrange_; |
883 |
24 Nov 09 |
jari |
184 |
PLFLT x=xmin_+1.7*line_length; |
883 |
24 Nov 09 |
jari |
185 |
unsigned char characteristic=log10(ymax_); |
883 |
24 Nov 09 |
jari |
186 |
PLFLT legend_lines_length=0.016*xrange_*(characteristic+1); |
883 |
24 Nov 09 |
jari |
187 |
PLFLT dx=0.005*xrange_; |
883 |
24 Nov 09 |
jari |
188 |
PLFLT dy=0.003*yrange_; |
883 |
24 Nov 09 |
jari |
189 |
unsigned int row=0; |
1325 |
23 Jan 11 |
peter |
190 |
std::vector<legend_data>::const_reverse_iterator end = legend_.rend(); |
1325 |
23 Jan 11 |
peter |
191 |
for (std::vector<legend_data>::const_reverse_iterator i=legend_.rbegin(); |
1325 |
23 Jan 11 |
peter |
192 |
i!=end; ++i, ++row) { |
883 |
24 Nov 09 |
jari |
193 |
PLFLT y=(0.95-0.04*row)*yrange_; |
929 |
02 Dec 09 |
jari |
194 |
current_color(*i); |
883 |
24 Nov 09 |
jari |
195 |
pls_.col0(1); |
883 |
24 Nov 09 |
jari |
196 |
pls_.join(x-line_length, y-dy, x, y-dy); |
883 |
24 Nov 09 |
jari |
197 |
std::stringstream ss; |
883 |
24 Nov 09 |
jari |
198 |
ss << i->lines; |
883 |
24 Nov 09 |
jari |
199 |
pls_.col0(2); |
883 |
24 Nov 09 |
jari |
200 |
pls_.ptex(x+legend_lines_length+dx*2, y, 0, 0, 0, i->label.c_str()); |
883 |
24 Nov 09 |
jari |
201 |
pls_.ptex(x+legend_lines_length+dx , y, 0, 0, 1, ss.str().c_str()); |
883 |
24 Nov 09 |
jari |
202 |
} |
902 |
27 Nov 09 |
peter |
203 |
#endif |
878 |
23 Nov 09 |
jari |
204 |
} |
878 |
23 Nov 09 |
jari |
205 |
|
878 |
23 Nov 09 |
jari |
206 |
|
1280 |
06 Nov 10 |
peter |
207 |
void Graph::rev_max(svn_revnum_t rev) |
1280 |
06 Nov 10 |
peter |
208 |
{ |
1280 |
06 Nov 10 |
peter |
209 |
rev_max_ = rev; |
1280 |
06 Nov 10 |
peter |
210 |
} |
1280 |
06 Nov 10 |
peter |
211 |
|
1280 |
06 Nov 10 |
peter |
212 |
|
1287 |
09 Nov 10 |
peter |
213 |
svn_revnum_t Graph::rev_max(void) |
1287 |
09 Nov 10 |
peter |
214 |
{ |
1287 |
09 Nov 10 |
peter |
215 |
return rev_max_; |
1287 |
09 Nov 10 |
peter |
216 |
} |
1287 |
09 Nov 10 |
peter |
217 |
|
1287 |
09 Nov 10 |
peter |
218 |
|
1255 |
01 Nov 10 |
peter |
219 |
void Graph::rev_min(svn_revnum_t rev) |
1255 |
01 Nov 10 |
peter |
220 |
{ |
1255 |
01 Nov 10 |
peter |
221 |
rev_min_ = rev; |
1255 |
01 Nov 10 |
peter |
222 |
} |
1255 |
01 Nov 10 |
peter |
223 |
|
1255 |
01 Nov 10 |
peter |
224 |
|
1287 |
09 Nov 10 |
peter |
225 |
svn_revnum_t Graph::rev_min(void) |
1287 |
09 Nov 10 |
peter |
226 |
{ |
1287 |
09 Nov 10 |
peter |
227 |
return rev_min_; |
1287 |
09 Nov 10 |
peter |
228 |
} |
1287 |
09 Nov 10 |
peter |
229 |
|
1287 |
09 Nov 10 |
peter |
230 |
|
1197 |
04 Oct 10 |
peter |
231 |
void Graph::set_dates(const std::vector<time_t>& date) |
875 |
23 Nov 09 |
jari |
232 |
{ |
1330 |
27 Jan 11 |
peter |
233 |
dates_=date; |
875 |
23 Nov 09 |
jari |
234 |
} |
875 |
23 Nov 09 |
jari |
235 |
|
875 |
23 Nov 09 |
jari |
236 |
|
1513 |
23 Sep 12 |
peter |
237 |
void Graph::staircase(svn_revnum_t rev0, PLFLT y0, |
1198 |
04 Oct 10 |
peter |
238 |
svn_revnum_t rev1, PLFLT y1) |
1198 |
04 Oct 10 |
peter |
239 |
{ |
1198 |
04 Oct 10 |
peter |
240 |
PLFLT x0 = rev0; |
1198 |
04 Oct 10 |
peter |
241 |
PLFLT x1 = rev1; |
1198 |
04 Oct 10 |
peter |
242 |
if (date_xticks()) { |
1418 |
25 Oct 11 |
peter |
243 |
assert(static_cast<size_t>(rev0)<dates_.size()); |
1330 |
27 Jan 11 |
peter |
244 |
assert(dates_[rev0]); |
1330 |
27 Jan 11 |
peter |
245 |
x0 = dates_[rev0]; |
1418 |
25 Oct 11 |
peter |
246 |
assert(static_cast<size_t>(rev1)<dates_.size()); |
1330 |
27 Jan 11 |
peter |
247 |
assert(dates_[rev1]); |
1330 |
27 Jan 11 |
peter |
248 |
x1 = dates_[rev1]; |
1198 |
04 Oct 10 |
peter |
249 |
} |
1198 |
04 Oct 10 |
peter |
250 |
#ifdef HAVE_PLPLOT |
1202 |
04 Oct 10 |
jari |
// join {x0,y0} with {x1,y1} via {x1,y0} |
1198 |
04 Oct 10 |
peter |
252 |
pls_.join(x0,y0,x1,y0); |
1198 |
04 Oct 10 |
peter |
253 |
pls_.join(x1,y0,x1,y1); |
1198 |
04 Oct 10 |
peter |
254 |
#endif |
1198 |
04 Oct 10 |
peter |
255 |
} |
1198 |
04 Oct 10 |
peter |
256 |
|
1198 |
04 Oct 10 |
peter |
257 |
|
1330 |
27 Jan 11 |
peter |
258 |
const std::vector<time_t>& Graph::dates(void) |
855 |
19 Nov 09 |
jari |
259 |
{ |
1330 |
27 Jan 11 |
peter |
260 |
return dates_; |
855 |
19 Nov 09 |
jari |
261 |
} |
855 |
19 Nov 09 |
jari |
262 |
|
855 |
19 Nov 09 |
jari |
263 |
|
882 |
24 Nov 09 |
jari |
264 |
double Graph::ymax(double ymax) |
855 |
19 Nov 09 |
jari |
265 |
{ |
882 |
24 Nov 09 |
jari |
266 |
return ymax_=ymax; |
855 |
19 Nov 09 |
jari |
267 |
} |
855 |
19 Nov 09 |
jari |
268 |
|
788 |
13 Apr 09 |
jari |
269 |
}} // end of namespace svndigest and namespace theplu |