lib/Graph.cc

Code
Comments
Other
Rev Date Author Line
788 13 Apr 09 jari 1 // $Id$
788 13 Apr 09 jari 2
788 13 Apr 09 jari 3 /*
1267 02 Nov 10 peter 4   Copyright (C) 2009, 2010 Jari Häkkinen, Peter Johansson
1635 30 Mar 23 peter 5   Copyright (C) 2011, 2023 Peter Johansson
788 13 Apr 09 jari 6
788 13 Apr 09 jari 7   This file is part of svndigest, http://dev.thep.lu.se/svndigest
788 13 Apr 09 jari 8
788 13 Apr 09 jari 9   svndigest is free software; you can redistribute it and/or modify it
788 13 Apr 09 jari 10   under the terms of the GNU General Public License as published by
788 13 Apr 09 jari 11   the Free Software Foundation; either version 3 of the License, or
788 13 Apr 09 jari 12   (at your option) any later version.
788 13 Apr 09 jari 13
788 13 Apr 09 jari 14   svndigest is distributed in the hope that it will be useful, but
788 13 Apr 09 jari 15   WITHOUT ANY WARRANTY; without even the implied warranty of
788 13 Apr 09 jari 16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
788 13 Apr 09 jari 17   General Public License for more details.
788 13 Apr 09 jari 18
788 13 Apr 09 jari 19   You should have received a copy of the GNU General Public License
788 13 Apr 09 jari 20   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 47     // should match the maximum number of authors plotted, change this
949 04 Dec 09 jari 48     // when the maximum number of authors becomes configurable
949 04 Dec 09 jari 49     legend_.reserve(10);
929 02 Dec 09 jari 50     // 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 77     // 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 86     // 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 108       // 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 251     // 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