contrib/brl/bbas/bxml/bsvg/bsvg_plot.cxx
Go to the documentation of this file.
00001 #include "bsvg_plot.h"
00002 //:
00003 // \file
00004 // \author Ozge C. Ozcanli (Brown)
00005 // \date   April 21, 2009
00006 
00007 #include <bxml/bxml_find.h>
00008 #include <bxml/bsvg/bsvg_element.h>
00009 #include <vcl_iostream.h>
00010 #include <vcl_sstream.h>
00011 
00012 void bsvg_plot::add_axes(float x_min, float x_max, float y_min, float y_max, float stroke_width)
00013 {
00014   float height_y = y_max - y_min;
00015   // find origin so that height of the plot is scaled wrt to the svg document width and height
00016   h2_y = h_ - 4*margin_;
00017   scale_factor_ = h2_y/height_y;
00018 
00019   axes_orig_x_ = 2*margin_;
00020   axes_orig_y_ = 2*margin_+h2_y;
00021 
00022   bsvg_line* line_y = new bsvg_line(axes_orig_x_, axes_orig_y_, axes_orig_x_, axes_orig_y_-h2_y-margin_);
00023   line_y->set_stroke_color("black");
00024   line_y->set_stroke_width(stroke_width);
00025 
00026   float height_x = x_max - x_min;
00027   // find origin so that height of the plot is scaled wrt to the svg document width and height
00028   h2_x = height_x*scale_factor_;
00029 
00030   bsvg_line* line_x = new bsvg_line(axes_orig_x_, axes_orig_y_, axes_orig_x_+h2_x+margin_, axes_orig_y_);
00031   line_x->set_stroke_color("black");
00032   line_x->set_stroke_width(stroke_width);
00033 
00034   this->add_element(line_y);
00035   this->add_element(line_x);
00036 
00037   // add text to denote x_min
00038   vcl_stringstream ss; ss << x_min;
00039   bsvg_text* t = new bsvg_text(ss.str());
00040   t->set_location(axes_orig_x_, axes_orig_y_+margin_);
00041   t->set_font_size(font_size_);
00042   this->add_element(t);
00043 
00044   // add text to denote y_min
00045   vcl_stringstream ssy; ssy << y_min;
00046   bsvg_text* ty = new bsvg_text(ssy.str());
00047   ty->set_location(axes_orig_x_-margin_, axes_orig_y_);
00048   ty->set_font_size(font_size_);
00049   this->add_element(ty);
00050 
00051   // add text to denote x_max
00052   vcl_stringstream ssx; ssx << x_max;
00053   bsvg_text* txm = new bsvg_text(ssx.str());
00054   txm->set_location(axes_orig_x_+h2_x, axes_orig_y_+margin_);
00055   txm->set_font_size(font_size_);
00056   this->add_element(txm);
00057 
00058   // add a short line to denote x_max
00059   bsvg_line* line_xm = new bsvg_line(axes_orig_x_ + h2_x, axes_orig_y_, axes_orig_x_ + h2_x, axes_orig_y_+(margin_/4.0f));
00060   line_xm->set_stroke_color("black");
00061   line_xm->set_stroke_width(stroke_width);
00062   this->add_element(line_xm);
00063 
00064   // add text to denote y_max
00065   vcl_stringstream ssym; ssym << y_max;
00066   bsvg_text* tym = new bsvg_text(ssym.str());
00067   tym->set_location(axes_orig_x_-margin_, axes_orig_y_-h2_y);
00068   tym->set_font_size(font_size_);
00069   this->add_element(tym);
00070 
00071   // add a short line to denote y_max
00072   bsvg_line* line_ym = new bsvg_line(axes_orig_x_-(margin_/4.0f), axes_orig_y_-h2_y, axes_orig_x_, axes_orig_y_-h2_y);
00073   line_ym->set_stroke_color("black");
00074   line_ym->set_stroke_width(stroke_width);
00075   this->add_element(line_ym);
00076 
00077   // put an arrow head at the end of x axis
00078   bsvg_arrow_head* a1 = new bsvg_arrow_head(axes_orig_x_+h2_x+margin_, axes_orig_y_, 10.0f);
00079   a1->set_stroke_width(stroke_width);
00080   a1->set_stroke_color("black");
00081   this->add_element(a1);
00082 
00083   // put an arrow head at the end of y axis
00084   bsvg_arrow_head* a2 = new bsvg_arrow_head(axes_orig_x_, axes_orig_y_-h2_y-margin_, 10.0f);
00085   a2->set_stroke_width(stroke_width);
00086   a2->set_rotation(-90);
00087   a2->set_stroke_color("black");
00088   this->add_element(a2);
00089 }
00090 
00091 void bsvg_plot::add_title(const vcl_string& t)
00092 {
00093   bsvg_text* title = new bsvg_text(t);
00094   float w = float(font_size_*t.size());
00095   title->set_location((this->w_-margin_)/2.0f - w/2, margin_);
00096   //title->set_location((h2_x+3*margin_-w)/2, margin_);
00097   title->set_font_size(font_size_);
00098   this->add_element(title);
00099 }
00100 
00101 //: assumes add_axes have been called
00102 void bsvg_plot::add_x_increments(float x_inc, float stroke_width)
00103 {
00104   float x_inc_scaled = scale_factor_*x_inc;
00105   bsvg_group* g = new bsvg_group();
00106   g->set_stroke_color("black");
00107   g->set_stroke_width(stroke_width);
00108   g->set_stroke_opacity(0.5);
00109 
00110   float end = axes_orig_x_ + h2_x;
00111   for (float x = axes_orig_x_ + x_inc_scaled; x <= end; x += x_inc_scaled) {
00112     bsvg_line* line_x = new bsvg_line(x, axes_orig_y_, x, axes_orig_y_-h2_y);
00113     g->add_element(line_x);
00114   }
00115   this->add_element(g);
00116 }
00117 
00118 //: assumes add_axes have been called
00119 void bsvg_plot::add_y_increments(float y_inc, float stroke_width)
00120 {
00121   float y_inc_scaled = scale_factor_*y_inc;
00122   bsvg_group* g = new bsvg_group();
00123   g->set_stroke_color("black");
00124   g->set_stroke_width(stroke_width);
00125   g->set_stroke_opacity(0.5);
00126 
00127   float end = axes_orig_y_ - h2_y;
00128   for (float y = axes_orig_y_ - y_inc_scaled; y >= end; y -= y_inc_scaled) {
00129     bsvg_line* line_y = new bsvg_line(axes_orig_x_, y, axes_orig_x_+h2_x, y);
00130     g->add_element(line_y);
00131   }
00132   this->add_element(g);
00133 }
00134 
00135 void bsvg_plot::add_line(const vcl_vector<float>& xs, const vcl_vector<float>& ys, const vcl_string& color, float stroke_width)
00136 {
00137   // scale the points to our plot
00138   if (xs.size() != ys.size()) {
00139     vcl_cout << " Error: bsvg_plot::add_line() - input vectors are not of the same size\n";
00140     return;
00141   }
00142   vcl_vector<float> xs_copy(xs);
00143   vcl_vector<float> ys_copy(ys);
00144   for (unsigned i = 0; i < xs.size(); i++) {
00145     xs_copy[i] = xs_copy[i]*scale_factor_ + axes_orig_x_;
00146     ys_copy[i] = axes_orig_y_ - ys_copy[i]*scale_factor_;
00147   }
00148 
00149   bsvg_polyline *pl = new bsvg_polyline(xs_copy, ys_copy);
00150   pl->set_stroke_color(color);
00151   pl->set_fill_color("none");
00152   pl->set_stroke_width(stroke_width);
00153 
00154   this->add_element(pl);
00155 }
00156 
00157 bsvg_group* bsvg_plot::add_bars_helper(const vcl_vector<float>& heights, const vcl_string& color)
00158 {
00159   bsvg_group* g = new bsvg_group();
00160   g->set_fill_color(color);
00161 
00162   int n = heights.size();
00163   // we will set bar margins bar_w/3
00164   float bar_w = h2_x / float(n + float(n + 1)/3.0f);
00165   float x = axes_orig_x_ + bar_w/3.0f; // left-point of first bar
00166   for (int i = 0; i < n; i++) {
00167     float h = heights[i]*scale_factor_;
00168     bsvg_rectangle *r = new bsvg_rectangle(x, axes_orig_y_-h, bar_w, h);
00169     g->add_element(r);
00170     x += bar_w/3 + bar_w;  // left-point of next bar, margin + bar width
00171   }
00172   return g;
00173 }
00174 
00175 bsvg_group* bsvg_plot::add_x_labels_helper(const vcl_vector<vcl_string>& x_labels, const vcl_string& color, bool vertical_labels)
00176 {
00177   bsvg_group* g = new bsvg_group();
00178   g->set_fill_color(color);
00179 
00180   int n = x_labels.size();
00181   // we will set bar margins bar_w/3
00182   float bar_w = h2_x / float(n + float(n + 1)/3.0f);
00183   float x = axes_orig_x_ + bar_w/2.0f + bar_w/3.0f; // mid-point of first bar
00184   for (int i = 0; i < n; i++) {
00185     bsvg_text *t = new bsvg_text(x_labels[i]);
00186     t->set_font_size(font_size_);
00187     t->set_location(x, axes_orig_y_+margin_);
00188     if (vertical_labels)
00189       t->set_rotation(90);
00190     g->add_element(t);
00191     x += bar_w/3.0f + bar_w;  // mid-point of next bar, margin + bar width
00192   }
00193   return g;
00194 }
00195 
00196 //: add equally spaced and equal width bars with the given heights
00197 void bsvg_plot::add_bars(const vcl_vector<float>& heights, const vcl_string& color)
00198 {
00199   bsvg_group* g = add_bars_helper(heights, color);
00200   this->add_element(g);
00201 }
00202 
00203 void bsvg_plot::add_bars(const vcl_vector<float>& heights, const vcl_vector<vcl_string>& x_labels, bool vertical_labels, const vcl_string& color)
00204 {
00205   bsvg_group* g = add_bars_helper(heights, color);
00206   this->add_element(g);
00207   bsvg_group* tg = add_x_labels_helper(x_labels, color, vertical_labels);
00208   this->add_element(tg);
00209 }
00210 
00211 void bsvg_plot::add_bars(const vcl_vector<float>& heights, const vcl_vector<float>& x_labels, bool vertical_labels, const vcl_string& color)
00212 {
00213   bsvg_group* g = add_bars_helper(heights, color);
00214   this->add_element(g);
00215   vcl_vector<vcl_string> x_ls;
00216   for (unsigned i = 0; i < x_labels.size(); i++) {
00217     vcl_stringstream ss; ss << x_labels[i];
00218     x_ls.push_back(ss.str());
00219   }
00220   bsvg_group* tg = add_x_labels_helper(x_ls, color, vertical_labels);
00221   this->add_element(tg);
00222 }
00223 
00224 //: recursive helper to find number of bars
00225 int number_of_bars_helper(bxml_data_sptr d)
00226 {
00227   bxml_element* r_elm = dynamic_cast<bxml_element*>(d.ptr());
00228   if (!r_elm)
00229     return 0;
00230 
00231   int cnt = 0;
00232   for (bxml_element::const_data_iterator it = r_elm->data_begin(); it != r_elm->data_end(); it++) {
00233     if ((*it)->type() != bxml_element::ELEMENT)
00234       continue;
00235     bxml_element* it_elm = dynamic_cast<bxml_element*>((*it).ptr());
00236     if (it_elm->name() == "rect")
00237       cnt++;
00238     else if (it_elm->name() == "g") {
00239       cnt += number_of_bars_helper(*it);
00240     }
00241   }
00242   return cnt;
00243 }
00244 
00245 int bsvg_plot::number_of_bars()
00246 {
00247   // get the root
00248   bxml_element query("svg");
00249   bxml_data_sptr root = bxml_find_by_name(this->root_element(), query);
00250   if (!root)
00251     return -1;
00252   return number_of_bars_helper(root);
00253 }
00254 
00255 //: add bars sequentially with a fixed interval and width.
00256 //  use margin_ as the width of each bar and leave margin_/3 intervals in between
00257 //  the total width of the plot needs to be adjusted during initialization to contain all desired number of bars
00258 int bsvg_plot::add_bar(const float height, const vcl_string& color)
00259 {
00260   // first find the next available bar location (count the number of rects in the document)
00261   int cnt = this->number_of_bars();
00262   if (cnt < 0) {
00263     vcl_cerr << "In bsvg_plot::add_bar() -- problems with the plot document!\n";
00264     return -1;
00265   }
00266   float x = axes_orig_x_ + margin_/3.0f; // left-point of first bar
00267   x += cnt*(margin_/3.0f + margin_);  // left-point of next bar, margin + bar width
00268   float h = height*scale_factor_;
00269   bsvg_rectangle *r = new bsvg_rectangle(x, axes_orig_y_-h, margin_, h);
00270   r->set_fill_color(color);
00271   this->add_element(r);
00272   return cnt;
00273 }
00274 
00275 int bsvg_plot::add_bar(const float height, const vcl_string& label, bool vertical_label, const vcl_string& color)
00276 {
00277   int cnt = add_bar(height, color);
00278   if (cnt < 0) {
00279     vcl_cerr << "In bsvg_plot::add_bar() -- problems with the plot document!\n";
00280     return -1;
00281   }
00282   float x = axes_orig_x_ + margin_/2.0f + margin_/3.0f; // mid-point of first text
00283   x += cnt*(margin_/3.0f + margin_);
00284   bsvg_text *t = new bsvg_text(label);
00285   t->set_font_size(font_size_);
00286   t->set_location(x, axes_orig_y_+margin_);
00287   if (vertical_label)
00288     t->set_rotation(90);
00289   this->add_element(t);
00290   return cnt;
00291 }
00292 
00293 int bsvg_plot::add_bar(const float height, const float x_label, bool vertical_label, const vcl_string& color)
00294 {
00295   vcl_stringstream ss; ss << x_label;
00296   return add_bar(height, ss.str(), vertical_label, color);
00297 }
00298 
00299 //: add splices for a pie chart
00300 void bsvg_plot::add_splice(float center_x, float center_y, float radius, float start_angle, float end_angle, const vcl_string& color)
00301 {
00302   bsvg_splice* splice_g = new bsvg_splice(center_x, center_y, radius, start_angle, end_angle);
00303   splice_g->set_fill_color(color);
00304   splice_g->set_stroke_color("black");
00305   this->add_element(splice_g);
00306 }
00307 
00308 void bsvg_plot::add_splice(float center_x, float center_y, float radius, float start_angle, float end_angle, unsigned red, unsigned green, unsigned blue)
00309 {
00310   bsvg_splice* splice_g = new bsvg_splice(center_x, center_y, radius, start_angle, end_angle);
00311   splice_g->set_fill_color(red, green, blue);
00312   splice_g->set_stroke_color("black");
00313   this->add_element(splice_g);
00314 }
00315