source: branches/0.9-stable/lib/Graph.cc @ 1276

Last change on this file since 1276 was 1276, checked in by Peter Johansson, 12 years ago

Let Graph class hold information about last point (rev_max_) rather
than defining via the size of Vector. Not resizing the Vectors means
we can avoid some copying in Stats class. But it also means we need to
handle the case of empty Vector in Stats::max_element. Made the
function Node::svn_info(void) public. In svndigest.cc set rev_min also
when not using dates as well as setting the new static variable rev_max.
closes #485

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 5.5 KB
Line 
1// $Id: Graph.cc 1276 2010-11-05 12:24:26Z peter $
2
3/*
4  Copyright (C) 2009, 2010 Jari Häkkinen, Peter Johansson
5
6  This file is part of svndigest, http://dev.thep.lu.se/svndigest
7
8  svndigest is free software; you can redistribute it and/or modify it
9  under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 3 of the License, or
11  (at your option) any later version.
12
13  svndigest is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with svndigest. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "Graph.h"
23
24#include "Date.h"
25
26#include <algorithm>
27#include <cassert>
28#include <cmath>
29#include <sstream>
30
31namespace theplu {
32namespace svndigest {
33
34  svn_revnum_t Graph::rev_max_=0;
35  svn_revnum_t Graph::rev_min_=0;
36  std::vector<time_t> Graph::xticks_;
37
38  Graph::Graph(const std::string& filename, const std::string& format)
39#ifdef HAVE_PLPLOT
40    : plots_(0), pls_(1,1,format.c_str(),filename.c_str()), timeformat_("%y-%b"),
41      title_(filename), xmin_(0.0), xmax_(0.0), ymin_(0.0), ymax_(0.0)
42  {
43    // should match the maximum number of authors plotted, change this
44    // when the maximum number of authors becomes configurable
45    legend_.reserve(10);
46    // we use color map 0 position 0 for background color
47    pls_.scolbga(255,255,255,0);
48    pls_.setopt("geometry", "600x500");
49    pls_.init();
50    pls_.adv(0);
51    pls_.vsta();
52    pls_.syax(6,0);
53  }
54#else
55{}
56#endif
57
58
59  Graph::~Graph(void)
60  {
61    print_legend();
62  }
63
64
65  bool Graph::date_xticks(void)
66  {
67    return xticks_.size() != 0;
68  }
69
70
71  void Graph::current_color(const legend_data& legend)
72  {
73    // we use color map 0 position 1 for current color
74#ifdef HAVE_PLPLOT
75    pls_.scol0a(1,legend.r,legend.g,legend.b,1.0);
76#endif
77  }
78
79
80  void Graph::current_color(unsigned char r, unsigned char g, unsigned char b)
81  {
82    // we use color map 0 position 1 for current color
83#ifdef HAVE_PLPLOT
84    pls_.scol0a(1,r,g,b,1.0);
85#endif
86  }
87
88
89  void Graph::plot(const SumVector& y, const std::string& label,
90                   unsigned int lines)
91  {
92#ifdef HAVE_PLPLOT
93    if (!plots_) {
94      assert(!date_xticks() || rev_min_<xticks_.size());
95      assert(!date_xticks() || xticks_[rev_min_]);
96      assert(rev_min_<xticks_.size() || !date_xticks());
97      xmin_= date_xticks() ? xticks_[rev_min_] : rev_min_;
98      assert(rev_max_<xticks_.size() || !date_xticks());
99      xmax_= date_xticks() ? xticks_[rev_max_] : rev_max_;
100      xrange_=xmax_-xmin_;
101      yrange_=ymax_-ymin_;
102      pls_.wind(xmin_, xmax_, ymin_, ymax_);
103
104      // draw plot frame, x and y ticks only for the first plot
105      pls_.scol0a(2,0,0,0,1.0);
106      pls_.col0(2);
107
108      std::string xopt("bcnstv");
109      if (date_xticks()) {
110        pls_.timefmt(timeformat_.c_str());
111        xopt="bcnstd";
112      }
113
114      unsigned int ytickspacing=tick_spacing(yrange_);
115      unsigned int xtickspacing=tick_spacing(xrange_);
116      pls_.box(xopt.c_str(), xtickspacing, 1, "bcnstv", ytickspacing, 2);
117      pls_.lab("Date", "Number of lines", title_.c_str());
118    }
119    ++plots_;
120
121    pls_.col0(1);
122
123    SumVector::const_iterator iter = y.begin();
124    svn_revnum_t x0=rev_min_;
125    PLFLT y0=0;
126    for (; iter!=y.end(); ++iter) {
127      staircase(x0, y0, iter->first, iter->second);
128      x0 = iter->first;
129      y0 = iter->second;
130    }
131    staircase(x0, y0, rev_max_, y0);
132
133    legend_data legend;
134    legend.label=label;
135    legend.lines=lines;
136    pls_.gcol0(1,legend.r,legend.g,legend.b);
137    legend_.push_back(legend);
138#endif
139  }
140
141
142  void Graph::print_legend(void)
143  {
144#ifdef HAVE_PLPLOT
145    PLFLT line_length=0.05*xrange_;
146    PLFLT x=xmin_+1.7*line_length;
147    unsigned char characteristic=log10(ymax_);
148    PLFLT legend_lines_length=0.016*xrange_*(characteristic+1);
149    PLFLT dx=0.005*xrange_;
150    PLFLT dy=0.003*yrange_;
151    unsigned int row=0;
152    std::reverse(legend_.begin(), legend_.end());
153    for (std::vector<legend_data>::const_iterator i=legend_.begin();
154         i!=legend_.end(); i++, ++row) {
155      PLFLT y=(0.95-0.04*row)*yrange_;
156      current_color(*i);
157      pls_.col0(1);
158      pls_.join(x-line_length, y-dy, x, y-dy);
159      std::stringstream ss;
160      ss << i->lines;
161      pls_.col0(2);
162      pls_.ptex(x+legend_lines_length+dx*2, y, 0, 0, 0, i->label.c_str());
163      pls_.ptex(x+legend_lines_length+dx  , y, 0, 0, 1, ss.str().c_str());
164    }
165#endif
166  }
167
168
169  void Graph::rev_max(svn_revnum_t rev)
170  {
171    rev_max_ = rev;
172  }
173
174
175  void Graph::rev_min(svn_revnum_t rev)
176  {
177    rev_min_ = rev;
178  }
179
180
181  void Graph::set_dates(const std::vector<time_t>& date)
182  {
183    xticks_=date;
184  }
185
186
187  void Graph::staircase(svn_revnum_t rev0, PLFLT y0, 
188                        svn_revnum_t rev1, PLFLT y1)
189  {
190    PLFLT x0 = rev0;
191    PLFLT x1 = rev1;
192    if (date_xticks()) {
193      assert(rev0<xticks_.size());
194      assert(xticks_[rev0]);
195      x0 = xticks_[rev0];
196      assert(rev1<xticks_.size());
197      assert(xticks_[rev1]);
198      x1 = xticks_[rev1];
199    }
200#ifdef HAVE_PLPLOT
201    // join {x0,y0} with {x1,y1} via {x1,y0}
202    pls_.join(x0,y0,x1,y0);
203    pls_.join(x1,y0,x1,y1);
204#endif
205  }
206
207
208  unsigned int Graph::tick_spacing(const double range) const
209  {
210    double frac=range/5;
211    unsigned char characteristic= static_cast<unsigned char>(std::log10(frac));
212    unsigned int power=static_cast<unsigned int>(std::pow(10.0, characteristic));
213    unsigned char msn=static_cast<unsigned char>(frac/power);
214    return power*msn;
215  }
216
217
218  void Graph::timeformat(const std::string& format)
219  {
220    timeformat_=format;
221  }
222
223
224  const std::vector<time_t>& Graph::xticks(void)
225  {
226    return xticks_;
227  }
228
229
230  double Graph::ymax(double ymax)
231  {
232    return ymax_=ymax;
233  }
234
235}} // end of namespace svndigest and namespace theplu
Note: See TracBrowser for help on using the repository browser.