ascii_chart.cxx

Go to the documentation of this file.
00001 #include <cxxtls/ascii_chart.h>
00002 #include <algorithm>
00003 #include <cxxtls/foreach.h>
00004 #include <string.h>
00005 #include <string>
00006 #include <portable_io.h>
00007 
00010 
00011 using std::fill_n;
00012 using std::ostream;
00013 using std::vector;
00014 using std::string;
00015 using std::endl;
00016 
00017 namespace cxxtls
00018 {
00019 
00020 ascii_chart::
00021 ascii_chart(int width, int height, char blank, char star)
00022 : width_(width),
00023   height_(height),
00024   blank_(blank),
00025   star_(star)
00026 {
00031   
00032   data_ = new char*[height+1];
00033 
00034   char **scan = data_;
00035 
00036   while(height)
00037   {
00038     *scan = new char[width+1];
00039 
00040     ++scan;
00041     --height;
00042   }
00043 
00044   *scan = 0;
00045 
00046   clear(); // sets dirty to false
00047 
00048 }
00049 
00050 ascii_chart::
00051 ~ascii_chart()
00052 {
00053   char** scan = data_;
00054 
00055   while(*scan)
00056   {
00057     delete [] *scan;
00058 
00059     ++scan;
00060   }
00061 
00062   delete [] data_;
00063 }
00064 
00065 void
00066 ascii_chart::
00067 clear()
00068 {
00070 
00071   dirty_ = false;
00072 
00073   char **scan;
00074 
00075   for(scan = data_; *scan; ++scan)
00076   {
00077     fill_n(*scan, width_, blank_);
00078     (*scan)[width_] = 0;
00079   }
00080 
00081   xrange_.first  = 0;
00082   xrange_.second = 0;
00083   yrange_.first  = 0;
00084   yrange_.second = 0;
00085 
00086 
00087 }
00088 
00089 void
00090 ascii_chart::
00091 range(data_t const &data)
00092 {
00093   //
00094   // First, compute the range of data
00095   //
00096 
00097   bool first_time=true;
00098 
00099   X_t xl=0;  // low/high vars
00100   X_t xh=0;
00101   Y_t yl=0;
00102   Y_t yh=0;
00103 
00104   data_t::const_iterator i = data.begin();
00105   data_t::const_iterator l = data.end();
00106 
00107   while(i != l)
00108   {
00109     X_t x = i->first;
00110     Y_t y = i->second;
00111     
00112     if(first_time)
00113     {
00114       xl = x;
00115       xh = x;
00116       yl = y;
00117       yh = y;
00118       first_time = false;
00119     }
00120     else
00121     {
00122       if(x < xl) xl = x;
00123       if(x > xh) xh = x;
00124       if(y < yl) yl = y;
00125       if(y > yh) yh = y;
00126     }
00127 
00128     ++i;
00129   }
00130 
00131   xrange_.first = xl;
00132   xrange_.second= xh;
00133   yrange_.first = yl;
00134   yrange_.second= yh;
00135 
00136 }
00137 
00138 void
00139 ascii_chart::
00140 plot(data_t const &data,int) // last parm is ignored
00141 {
00142 
00143   if(dirty_)
00144     clear();
00145 
00146   range(data);   // get extrema for the data
00147 
00148   // when plotting, we'll bias the data in the range 0 to width_, 0 to height_
00149 
00150   X_t x_span = xrange_.second - xrange_.first;
00151   Y_t y_span = yrange_.second - yrange_.first;
00152 
00153 
00154 
00155   CXXTLS_FOREACH(data_t::value_type const &i, data)
00156   {
00157     X_t x = i.first;
00158     Y_t y = i.second;
00159 
00160     // slide the input data so that runs from 0 - x_span, 0 - y_span
00161 
00162     x -= xrange_.first;
00163     y -= yrange_.first;
00164 
00165     // scale the data so it fits in the range 0-width, 0-height
00166 
00167     x *= width_;
00168     x /= x_span;
00169 
00170     y *= height_;
00171     y /= y_span;
00172 
00173     // clamp the data so no array index errors are likely
00174 
00175     int x_int = static_cast<int>(x);
00176     int y_int = static_cast<int>(y);
00177 
00178     if(x_int <  0)      x_int = 0;
00179     if(x_int >= width_) x_int = width_-1;
00180 
00181     if(y_int < 0)        y_int = 0;
00182     if(y_int >= height_) y_int = height_ -1;
00183 
00184     data_[height_-1 - y_int][x_int]=star_;
00185 
00186   }
00187 
00188   dirty_ = true;
00189 
00190   
00191 }
00192 
00193 static void detrail(char *s)
00194 {
00195   size_t l = strlen(s);
00196 
00197   while(l)
00198   {
00199     --l;
00200 
00201     if(s[l] != '0' &&
00202        s[l] != '.' &&
00203        s[l] != '-'
00204       )
00205     {
00206       s[l+1] = 0;
00207       return;
00208     }
00209   }
00210 
00211   if(l == 0)
00212   {
00213     s[0] = '0';
00214     s[1] = 0;
00215   }
00216 
00217 }
00218 
00219 
00220 void
00221 ascii_chart::
00222 print_helper(ostream& stream) const
00223   // print the chart and add right side and bottom annotations
00224 {
00225   int i;
00226 
00227   //
00228   //  Print the stars and the horizontal annotations
00229   //
00230 
00231   {
00232     string tmp;
00233 
00234     if(static_cast<int>(width_) > static_cast<int>(title_.size()))
00235     {
00236       int count = (width_ - title_.size()) / 2;
00237 
00238       while(count--)
00239         tmp += ' ';
00240 
00241       stream << tmp << title_ << endl;
00242 
00243     }
00244     else
00245       stream << title_ << endl;
00246   }
00247 
00248 
00249   for(i=0; i < height_; ++i)
00250   {
00251     stream << data_[i] << "|";
00252 
00253     if( i == 0)
00254       stream << yrange_.second;
00255     else
00256     if( i == height_-1)
00257       stream << yrange_.first;
00258     else
00259     if( i == height_/2)
00260       stream << (yrange_.first + yrange_.second)/2;
00261 
00262     stream << endl;
00263     
00264   }
00265 
00266   //
00267   // put a row of dashes at the bottom of the stars and blanks plot
00268   //
00269   {
00270     string tmp;
00271     
00272     for(i=0; i < width_; ++i)
00273     {
00274       tmp += '-';
00275     }
00276     
00277     tmp += '+';
00278     
00279     stream << tmp << endl;
00280   }
00281 
00282   //
00283   //  Print the X annotations by manually printing the individual characters
00284   //  of the x range vertically instead of horizontally.
00285   //
00286 
00287   char buffer1[1000];
00288   char buffer2[1000];
00289 
00290   sprintf(buffer1, "%f", xrange_.first);
00291   sprintf(buffer2, "%f", xrange_.second);
00292 
00293   detrail(buffer1);
00294   detrail(buffer2);
00295 
00296   int b1_len = strlen(buffer1);
00297   int b2_len = strlen(buffer2);
00298 
00299   int max_len = (b1_len > b2_len ) 
00300                   ? b1_len 
00301                   : b2_len;
00302 
00303   vector<string> bottom(max_len);
00304 
00305   for(i=0; i < max_len; ++i)
00306   {
00307     int j;
00308 
00309     for(j=0; j < width_; ++j)
00310       bottom[i] += ' ';
00311   }
00312 
00313   for(i=0; i < b1_len; ++i)
00314     bottom[i][0] = buffer1[i];
00315 
00316   for(i=0; i < b2_len; ++i)
00317     bottom[i][width_-1] = buffer2[i];
00318 
00319   for(i=0; i < max_len; ++i)
00320    stream << bottom[i].c_str() << endl;
00321   
00322 }
00323 } // namespace cxxtls
Generated on Wed Feb 29 22:50:04 2012 for CXXUtilities by  doxygen 1.6.3