Boost logo

Boost-Commit :

From: pbristow_at_[hidden]
Date: 2007-12-11 10:53:53


Author: pbristow
Date: 2007-12-11 10:53:51 EST (Tue, 11 Dec 2007)
New Revision: 41965
URL: http://svn.boost.org/trac/boost/changeset/41965

Log:
many improvements (legend box position option) but still plot and text_style TODO.
Text files modified:
   sandbox/SOC/2007/visualization/boost/svg_plot/detail/axis_plot_frame.hpp | 421 +++++++++++++++++++++++++++++++--------
   sandbox/SOC/2007/visualization/boost/svg_plot/detail/svg_tag.hpp | 46 ++-
   sandbox/SOC/2007/visualization/boost/svg_plot/svg.hpp | 63 +++++
   sandbox/SOC/2007/visualization/boost/svg_plot/svg_2d_plot.hpp | 392 +++++++++++++++++++++---------------
   sandbox/SOC/2007/visualization/boost/svg_plot/svg_style.hpp | 222 ++++++++++++++++++---
   5 files changed, 842 insertions(+), 302 deletions(-)

Modified: sandbox/SOC/2007/visualization/boost/svg_plot/detail/axis_plot_frame.hpp
==============================================================================
--- sandbox/SOC/2007/visualization/boost/svg_plot/detail/axis_plot_frame.hpp (original)
+++ sandbox/SOC/2007/visualization/boost/svg_plot/detail/axis_plot_frame.hpp 2007-12-11 10:53:51 EST (Tue, 11 Dec 2007)
@@ -64,6 +64,55 @@
     // void clear_plot_background();
     // void clear_grids();
 
+ const std::string strip(std::string s)
+ { // Ugly hack to remove unwanted sign and leading zero in exponent.
+ // TODO It alters the layout because space
+ // is still allowed for the longest string.
+ // Would need to work out the longest value label before calculate_plot_window.
+ // But should be useful for values that spill over into exponent format
+ // 'by accident' - when leading zeros are likely.
+ using std::string;
+ size_t j = s.find("e+000");
+ if (j != string::npos)
+ {
+ s.erase(j, 5); // remove "e+000"
+ goto ret;
+ }
+ j = s.find("e-000");
+ if (j != string::npos)
+ {
+ s.erase(j, 5); // remove "e-000"
+ goto ret;
+ }
+ j = s.find("e+00");
+ if (j != string::npos)
+ {
+ s.erase(j + 1, 3); // remove "+00"
+ goto ret;
+ }
+
+ j = s.find("e-00");
+ if (j != string::npos)
+ {
+ s.erase(j+2, 2); // remove "00", leave "-"
+ goto ret;
+ }
+ j = s.find("e+0");
+ if (j != string::npos)
+ {
+ s.erase(j + 1, 2); // remove "+0"
+ goto ret;
+ }
+ j = s.find("e-0");
+ if (j != string::npos)
+ {
+ s.erase(j+2, 1); // remove "0", leave "-"
+ goto ret;
+ }
+ ret:
+ return s;
+ } // const std::string strip(double d)
+
     void transform_point(double& x, double& y)
     { // Scale & shift both x & y to graph coordinate.
       x = derived().x_scale * x + derived().x_shift;
@@ -85,11 +134,11 @@
     }
 
     void draw_x_minor_ticks(double value, path_element& tick_path, path_element& grid_path)
- { // draw X-axis minor ticks, and optional grid.
- // value is NOT (yet) shown beside the minor tick.
+ { // Draw X-axis minor ticks, and optional grid.
+ // Value is NOT (yet) shown beside the minor tick.
       double x1(value);
       transform_x(x1);
- double y1(0.);
+ double y1(0.); // Start on the horizontal X-axis line.
       double y2(derived().image.y_size());
 
       // Draw the minor grid, if wanted.
@@ -142,8 +191,8 @@
         }
       }
       else
- { // Internal style, draw tick up and/or down from the central X axis line.
- y1 = derived().x_axis; // X-axis line.
+ { // Internal style, draw tick up and/or down from the X-axis line.
+ y1 = derived().x_axis; // X-axis horizontal line.
         y2 = derived().x_axis;
         if(derived().use_up_ticks)
         {
@@ -238,6 +287,11 @@
         label.precision(derived().x_value_precision_);
         label.flags(derived().x_value_ioflags_);
         label << value; // "1.2" or "3.4e+000"...
+ if (derived().strip_e0s_)
+ { // remove unecessary e, +, leadings 0s
+ std::string v = strip(label.str());
+ label.str(v);
+ }
         double y = y2; // bottom end of the tick.
         align_style alignment = center_align;
         if(derived().use_down_ticks)
@@ -279,7 +333,8 @@
           { // Avoid a "0" below the X-axis if it would be cut through by any internal vertical Y-axis line.
            derived().image.get_g_element(detail::PLOT_VALUE_LABELS).text(
               x1, y,
- label.str(), derived().x_label_value.font_size(), derived().x_label_value.font_family(),
+ label.str(),
+ derived().x_label_value.font_size(), derived().x_label_value.font_family(),
               "", "", "", "", alignment, // center label on the tick.
               derived().x_label_rotation_);
           }
@@ -305,46 +360,70 @@
     path_element& major_grid_path = derived().image.get_g_element(PLOT_X_MAJOR_GRID).path();
 
     if(derived().use_x_axis_lines_)
- { // Draw the horizontal X-axis line the full width of the plot window.
+ { // Draw the horizontal X-axis line the full width of the plot window,
+ // including an addition in lieu of a major tick.
+ double xleft = derived().plot_x1;
+ double yaxis = derived().x_axis; // y = 0
+ if (derived().use_left_ticks)
+ { // Extend the horizontal line left in lieu of longest tick.
+ xleft -= (std::max)(derived().y_minor_tick_length_, derived().y_major_tick_length_);
+ }
       derived().image.get_g_element(PLOT_X_AXIS).line(
- derived().plot_x1, derived().x_axis, // y = 0
- derived().plot_x2, derived().x_axis); // y = 0
+ xleft, yaxis,
+ derived().plot_x2, yaxis);
     }
 
     // x_minor_jump is the interval between minor ticks.
     double x_minor_jump = derived().x_major_interval_ /
       (derived().x_num_minor_ticks_ + 1.);
 
- // TODO Problem here when using floating point??
- // Was i < y_max; but didn't show the tick and value at y_max so now i <= y_max;
- // But may still fail if a least significant bit or few out??
-
     // Draw the ticks on the positive side (right of zero).
     for(double x = 0.; x <= derived().x_max; x += derived().x_major_interval_)
     {
- for(double j = x + x_minor_jump; j < x + derived().x_major_interval_; j += x_minor_jump)
+ for(double j = x + x_minor_jump;
+ j < (x + derived().x_major_interval_) * (1. - 2 * std::numeric_limits<double>::epsilon());
+ j += x_minor_jump)
+ // Reduce test value by a few bits to avoid accumulated rounding error
+ // that intermittently puts minor ticks *at same value as* major ticks.
       { // This will output 'orphaned' minor ticks that are beyond the plot window,
         // if the last major tick does not coincide with the plot window.
         // These are just ignored in draw_x_minor_ticks.
- // There might be 9 of them,
+ // There might be 9 of them, so
         // if you have the common 9 minor tick between major ticks!
         // TODO this seems ugly - as does the negative ones below.
         draw_x_minor_ticks(j, minor_tick_path, minor_grid_path);
+ } // for j
+ if ((x != 0. || !derived().use_y_axis_lines_) || derived().use_x_ticks_on_plot_window_)
+ { // Avoid a major tick at x == 0 where there *is* a vertical Y-axis line.
+ // (won't be Y-axis line for 1-D where the zero tick is always wanted).
+ draw_x_major_ticks(x, major_tick_path, major_grid_path);
       }
- draw_x_major_ticks(x, major_tick_path, major_grid_path);
     }
 
     // Draw the ticks on the negative side (left of zero).
- for(double x = 0; x >= derived().x_min; x -= derived().x_major_interval_)
+ for(double x = 0.; x >= derived().x_min; x -= derived().x_major_interval_)
     {
       // Draw minor ticks.
- for(double j = x;
- j > x-derived().x_major_interval_;
- j-= derived().x_major_interval_ / (derived().x_num_minor_ticks_+1))
+ for(double j = x - x_minor_jump;
+ j > (x - derived().x_major_interval_ + x_minor_jump) * (1. + 2 * std::numeric_limits<double>::epsilon());
+ // Increase test value by a few bits to avoid accumulated rounding error
+ // that intermittently puts minor ticks *at same value as* major ticks.
+
+ j -= x_minor_jump)
       {
- draw_x_minor_ticks(j, minor_tick_path, minor_grid_path);
+ if ((j != 0. || !derived().use_y_axis_lines_) || derived().use_x_ticks_on_plot_window_)
+ { // Avoid a minor tick at x == 0 where there *is* a vertical Y-axis line.
+ // (won't be Y-axis line for 1-D where the zero tick is always wanted).
+ // But no tick means no value label 0 either unless on_plot_window.
+ draw_x_minor_ticks(j, minor_tick_path, minor_grid_path);
+ }
+ }
+ if ((x != 0. || !derived().use_y_axis_lines_) || derived().use_x_ticks_on_plot_window_)
+ { // Avoid a major tick at x == 0 where there *is* a vertical Y-axis line.
+ // (won't be Y-axis line for 1-D where the zero tick is always wanted).
+ // But no tick means no value label 0 either unless on_plot_window.
+ draw_x_major_ticks(x, major_tick_path, major_grid_path);
       }
- draw_x_major_ticks(x, major_tick_path, major_grid_path);
     }
   } // void draw_x_axis()
 
@@ -354,14 +433,6 @@
 
   void draw_title()
   {
- // text_element::text_element(double x, double y,
- // const std::string&,
- // int size,
- // const std::string& font,
- // const std::string& style, const std::string& weight,
- // const std::string& stretch, const std::string& decoration,
- // int align, int rotate);
-
     // Update title_info with position.
     derived().title_info.x(derived().image.x_size() / 2.); // Center of image.
     // Assumes align = center_align.
@@ -369,29 +440,44 @@
     if (derived().use_plot_window)
     {
        y = derived().plot_y1; // plot_y1 IS now assigned in calculate_plot_window
- // Center the title in the space between top and plot window top.
- y /= 2;
+ // y is distance from top of image to top of plot window.
+ y /= derived().text_margin_; // Center the title in the space between.
     }
     else
- { // use all image.
+ { // Using all image.
       y = derived().title_info.font_size() * derived().text_margin_; // Leave a linespace above.
     }
     derived().title_info.y(y);
     derived().image.get_g_element(PLOT_TITLE).push_back(new text_element(derived().title_info));
   } // void draw_title()
 
- void draw_legend()
+ void calculate_legend_box()
   {
- size_t num_points = derived().series.size();
+ if(derived().use_legend == false)
+ { // No legend.
+ // TODO might this overwrite some previous useful values?
+ // Set values to show legend position invalid.
+ derived().legend_x1_ = -1;
+ derived().legend_x2_ = -1;
+ derived().legend_y1_ = -1;
+ derived().legend_y2_ = -1;
+ return;
+ }
+
+ // Work out the size the legend box needs to be to hold the
+ // header, markers & text.
+ size_t num_series = derived().series.size(); // How many data series.
     int font_size = derived().legend_header_.font_size();
- int point_size = derived().series[0].point_style.size;
- // Use whichever is the biggest of point marker and font.
+ int point_size = derived().series[0].point_style.size();
+ // Use height of whichever is the biggest of point marker and font.
 
     double spacing = (std::max)(font_size, point_size);
- // std::cerr << spacing << ' ' << font_size << ' ' << point_size << endl;
+ std::cout << spacing << ' ' << font_size << ' ' << point_size << endl;
     bool is_header = (derived().legend_header_.text() != "");
- size_t longest = 0;
- for(unsigned int i = 0; i < derived().series.size(); ++i)
+
+ size_t longest = derived().legend_header_.text().size();
+ // 0 if no header.
+ for(unsigned int i = 0; i < num_series; ++i)
     { // Find the longest text in all the data series.
       std::string s = derived().series[i].title;
       size_t siz = s.size();
@@ -400,56 +486,204 @@
         longest = siz;
       }
     }
- double legend_width = (6 + longest /2) * spacing;
- // font_size is not exact because width varies.
- // Allow for a leading space, data marker symbol, space,
- // line in color (only if 2-D and line option selected TODO)
- // space, text, trailing space before box margin.
+ cout.flags(std::ios_base::dec);
+ std::cout << "Longest legend header or data descriptor " << longest << std::endl; // TODO remove.
+
+ const double wh = 0.7; // TODO share a common value?
+ // font_size is not exact because width varies but use 0.7.
+ double legend_width = (0 + longest) * wh * font_size;
+ // Allow for a leading space, longest
+ // & trailing space before box margin.
+ if (derived().use_line)
+ { // colored line marker.
+ legend_width += spacing;
+ }
+ if(derived().series[0].point_style.shape() != none)
+ { // colored data point marker, cross, round... & space
+ legend_width += 2 * derived().series[0].point_style.size();
+ }
+ // else no point marker.
 
     // legend_height must be *at least* enough for
- // the legend title and text_margin_s around it
+ // any legend header and text_margin_s around it
     // (if any) plus a text_margin_ top and bottom.
     // Add more height depending on the number of lines of text.
- double legend_height = spacing;
- if ( (derived().use_title) // plot title
- && (derived().legend_header_.text() != "")) // & really is a legend title.
+ double legend_height = spacing; // At top
+ if (is_header) // is a legend header.
     {
- legend_height += 2 * spacing;
+ legend_height += 2 * font_size; // text & space after.
+ }
+ legend_height += num_series * spacing * 2; // Space for the data point symbols & text.
+
+ if ( (derived().legend_x1_ != -1)
+ && (derived().legend_y1_ != -1))
+ { // Specific legend box top left position is requested.
+ // Check if the location requested will fit,
+ // now that we know the size of box needed.
+ if ((derived().legend_x1_ < 0) || (derived().legend_x1_ > derived().image.x_size()))
+ { // left outside image.
+ cout << "Legend X left " << derived().legend_x1_
+ << " outside image!" << derived().image.x_size() << endl;
+ }
+ else if ((derived().legend_y1_ < 0) || (derived().legend_y1_ > derived().image.y_size()))
+ {// Outside image.
+ cout << "Legend Y top " << derived().legend_y1_
+ << " outside image!" << derived().image.y_size() << endl;
+ }
+ if (derived().legend_x1_ + legend_height > derived().image.x_size())
+ { // Too wide!
+ cout << "Legend " << derived().legend_x1_
+ << " too wide by " << legend_width - derived().image.x_size() << endl;
+ }
+ else if (derived().legend_y1_ + legend_height > derived().image.y_size())
+ {
+ cout << "Legend Y left " << derived().legend_y1_
+ << " too high by " << legend_height - derived().image.y_size() << endl;
+ }
+ // else
+ //throw?
+ // or Set anyway.
+ derived().legend_width_ = legend_width;
+ derived().legend_height_ = legend_height;
+ // derived().legend_.x1 & y1 are OK.
+ derived().legend_x2_ = derived().legend_x1_ + legend_width;
+ derived().legend_y2_ = derived().legend_y1_ + legend_height;
+ }
+ else
+ { // default legend position position.
+ // x, y position of legend 'box' top left,
+ // default is level with top right of plot window, right by a small space.
+ double legend_x_start = derived().plot_x2;
+ legend_x_start += spacing; // leave a space between plot window and legend box.
+ double legend_y_start = derived().plot_y1;
+ legend_y_start += derived().title_info.font_size() * 2;
+ // leave space for title between image top and legend box.
+
+ // Check if the default location will fit,
+ // now that we know the size of box needed.
+ if ((legend_x_start < 0) || (legend_x_start > derived().image.x_size()))
+ { // Outside image - should never happen but check anyway?
+ cout << "Legend X left " << legend_x_start
+ << " outside image!" << derived().image.x_size() << endl;
+ }
+ else if ((legend_y_start < 0) || (legend_y_start > derived().image.y_size()))
+ { // Outside image - should never happen but check anyway?
+ cout << "Legend Y top " << legend_y_start
+ << " outside image!" << derived().image.y_size() << endl;
+ }
+ if (derived().legend_header_.x() + legend_height > derived().image.x_size())
+ { // Too wide!
+ cout << "Legend " << derived().legend_header_.x()
+ << " too wide by " << legend_width - derived().image_x_size() << endl;
+ }
+ else if (derived().legend_header_.y() + legend_height > derived().image.y_size())
+ {
+ cout << "Legend Y left " << derived().legend_header_.y()
+ << " too high by " << legend_height - derived().image.y_size() << endl;
+ }
+ else
+ { // throw? or set anyway.
+ }
+ derived().legend_width_ = legend_width;
+ derived().legend_height_ = legend_height;
+ derived().legend_x1_ = legend_x_start;
+ derived().legend_x2_ = legend_x_start + legend_width;
+ derived().legend_y1_ = legend_y_start;
+ derived().legend_y2_ = legend_y_start + legend_height;
     }
- legend_height += num_points * spacing * 2; // Space for the point symbols & text.
 
- // x, y position of legend 'box' top left, level with top right of plot window.
- double legend_x_start(derived().plot_x2);
- legend_x_start += spacing; // leave a space between plot window and legend box.
- double legend_y_start(derived().plot_y1);
-
- int x_size = derived().image.x_size();
- if((legend_x_start + legend_width) > x_size)
- { // Use nearly all the image width available.
- std::cout << "Legend text line was too long by "
- << ((legend_x_start + legend_width) - x_size)
- << " pixels, & so truncated. legend_width == " << legend_width << std::endl;
- // For example:
- // "Legend text line was too long by about 84 pixels & so truncated. legend_width == 252"
- legend_width = x_size - legend_x_start - spacing; // derived().text_margin_;
- // text_margin_ just allows the border box to show.
+ // Draw border box round legend.
+ g_element* g_ptr = &(derived().image.get_g_element(PLOT_LEGEND_BACKGROUND));
+ g_ptr->push_back(new
+ rect_element(derived().legend_x1_, derived().legend_y1_, legend_width, legend_height));
+
+ cout << "Legend width " << derived().legend_width_ << ", height "
+ << derived().legend_height_ << ", top left "
+ << derived().legend_x1_ << ", top right "
+ << derived().legend_x2_ << ", bottom left "
+ << derived().legend_y1_ << ", botton right "
+ << derived().legend_y2_ << endl;
+
+ } // void calculate_legend_box()
+
+ void draw_legend()
+ {
+ // size_t num_points = derived().series.size();
+ int font_size = derived().legend_header_.font_size();
+ int point_size = derived().series[0].point_style.size();
+ // Use whichever is the biggest of point marker and font.
+
+ double spacing = (std::max)(font_size, point_size);
+ // std::cerr << spacing << ' ' << font_size << ' ' << point_size << endl;
+ bool is_header = (derived().legend_header_.text() != "");
+
+
+ // TODO use saved version
+ size_t longest = 0;
+ for(unsigned int i = 0; i < derived().series.size(); ++i)
+ { // Find the longest text in all the data series.
+ std::string s = derived().series[i].title;
+ size_t siz = s.size();
+ if (siz > longest)
+ {
+ longest = siz;
+ }
     }
 
+
+ //double legend_width = (6 + longest /2) * spacing;
+ //// font_size is not exact because width varies.
+ //// Allow for a leading space, data marker symbol, space,
+ //// line in color (only if 2-D and line option selected TODO)
+ //// space, text, trailing space before box margin.
+
+ //// legend_height must be *at least* enough for
+ //// the legend title and text_margin_s around it
+ //// (if any) plus a text_margin_ top and bottom.
+ //// Add more height depending on the number of lines of text.
+ //double legend_height = spacing;
+ //if ( (derived().use_title) // plot title
+ // && (derived().legend_header_.text() != "")) // & really is a legend title.
+ //{
+ // legend_height += 2 * spacing;
+ //}
+ //legend_height += num_points * spacing * 2; // Space for the point symbols & text.
+
+ //// x, y position of legend 'box' top left, level with top right of plot window.
+ //double legend_x_start(derived().plot_x2);
+ //legend_x_start += spacing; // leave a space between plot window and legend box.
+ //double legend_y_start(derived().plot_y1);
+
+ //if((legend_x_start + legend_width) > x_size)
+ //{ // Use nearly all the image width available.
+ // std::cout << "Legend text line was too long by "
+ // << ((legend_x_start + legend_width) - x_size)
+ // << " pixels, & so truncated. legend_width == " << legend_width << std::endl;
+ // // For example:
+ // // "Legend text line was too long by about 84 pixels & so truncated. legend_width == 252"
+ // legend_width = x_size - legend_x_start - spacing; // derived().text_margin_;
+ // // text_margin_ just allows the border box to show.
+ //}
+
+ // Assume legend box position has already been sized and positioned by calculate_legend_box
+
+ double legend_x_start = derived().legend_x1_; // Saved box location.
+ double legend_width = derived().legend_width_;
+ double legend_y_start = derived().legend_y1_;
+ double legend_height = derived().legend_height_;
+
     // Draw border box round legend.
     g_element* g_ptr = &(derived().image.get_g_element(PLOT_LEGEND_BACKGROUND));
     g_ptr->push_back(new
       rect_element(legend_x_start, legend_y_start, legend_width, legend_height));
- derived().legend_x1_ = legend_x_start; // Save for access by legend_to_left.
- derived().legend_x2_ = legend_width;
- derived().legend_y1_ = legend_y_start; // and legend_bottom_right.
- derived().legend_y2_ = legend_height;
 
     double legend_y_pos = legend_y_start + derived().text_margin_ * spacing;
     if (is_header)
- { // Draw the legend text.
+ { // Draw the legend header text "My Plot Legend".
       derived().legend_header_.x(legend_x_start + legend_width / 2.); // / 2. to center in legend box.
       derived().legend_header_.y(legend_y_pos);
- derived().image.get_g_element(PLOT_LEGEND_TEXT).push_back(new text_element(derived().legend_header_));
+ derived().image.get_g_element(PLOT_LEGEND_TEXT).push_back(new
+ text_element(derived().legend_header_));
       legend_y_pos += 2 * spacing;
     }
 
@@ -463,9 +697,9 @@
       g_inner_ptr = &(g_ptr->add_g_element());
       // Use both fill & stroke colors from the point's style.
       g_inner_ptr->style()
- .fill_color(derived().series[i].point_style.fill_color)
- .stroke_color(derived().series[i].point_style.stroke_color);
- if(derived().series[i].point_style.shape != none)
+ .fill_color(derived().series[i].point_style.fill_color_)
+ .stroke_color(derived().series[i].point_style.stroke_color_);
+ if(derived().series[i].point_style.shape() != none)
       {
         draw_plot_point( // Plot point like circle, square...
           legend_x_start + spacing, // space before point marker.
@@ -573,7 +807,7 @@
     g_element& g_ptr,
     const plot_point_style& sty)
   {
- int size = sty.size;
+ int size = sty.size_;
     double half_size = size / 2.;
 
     // For 1-D plots, the points do not *need* to be centered on the X-axis,
@@ -587,7 +821,7 @@
     // the vertical and horizontal ticks are deliberately offset above the axes.
     // TODO Not sure this is fully resolved.
 
- switch(sty.shape) // from enum point_shape none, round, square, point, egg
+ switch(sty.shape_) // from enum point_shape none, round, square, point, egg
     {
     case round:
       g_ptr.circle(x, y, half_size);
@@ -622,7 +856,7 @@
       break;
 
     case symbol:
- g_ptr.text(x, y + half_size, sty.symbols, size, "Lucida Sans Unicode"); // symbol(s), size and centre.
+ g_ptr.text(x, y + half_size, sty.symbols_, size, "Lucida Sans Unicode"); // symbol(s), size and centre.
       // TODO Need to provide way to set style.symbols when Boost.Parameter is unravelled.
 
       // Unicode symbols that work on most browsers are listed at
@@ -904,7 +1138,6 @@
 
   Derived& image_size(unsigned int x, unsigned int y)
   { // Might put default sizes here?
- // Might also alow to set x and y separately?
     // Check on sanity of these values?
     derived().image.image_size(x, y);
     return derived();
@@ -1110,6 +1343,17 @@
     return derived().title_info.font_weight();
   }
 
+ Derived& legend_font_weight(const std::string& weight)
+ {
+ derived().legend_header_.font_weight(weight);
+ return derived();
+ }
+
+ const std::string& legend_font_weight()
+ {
+ return derived().legend_header_.font_weight();
+ }
+
   Derived& title_font_stretch(const std::string& stretch)
   {
     derived().title_info.font_stretch(stretch);
@@ -1693,22 +1937,18 @@
   }
 
   Derived& x_axis_color(const svg_color& col)
- { // Note BOTH fill and stroke color are set (and are the same).
- // stroke is the outside of any character, fill the center color.
- // TODO But the axis is only a line, so set both for tidyness?
- derived().image.get_g_element(PLOT_X_AXIS).style().fill_color(col);
+ { // Note only stroke color is set.
     derived().image.get_g_element(PLOT_X_AXIS).style().stroke_color(col);
     return derived();
   }
 
   svg_color x_axis_color()
- { // Assumes that fill and stroke colors are the same.
+ {
     return derived().image.get_g_element(PLOT_X_AXIS).style().stroke_color();
   }
 
   Derived& y_axis_color(const svg_color& col)
   {
- derived().image.get_g_element(PLOT_Y_AXIS).style().fill_color(col);
     derived().image.get_g_element(PLOT_Y_AXIS).style().stroke_color(col);
     return derived();
   }
@@ -1832,6 +2072,17 @@
     return derived().image.get_g_element(PLOT_X_AXIS).style().stroke_width();
   }
 
+ Derived& data_lines_width(double width)
+ {
+ derived().image.get_g_element(PLOT_DATA_LINES).style().stroke_width(width);
+ return derived();
+ }
+
+ double data_lines_width()
+ {
+ return derived().image.get_g_element(PLOT_DATA_LINES).style().stroke_width();
+ }
+
   Derived& x_label(const std::string& str)
   {
     derived().x_label_info.text(str);

Modified: sandbox/SOC/2007/visualization/boost/svg_plot/detail/svg_tag.hpp
==============================================================================
--- sandbox/SOC/2007/visualization/boost/svg_plot/detail/svg_tag.hpp (original)
+++ sandbox/SOC/2007/visualization/boost/svg_plot/detail/svg_tag.hpp 2007-12-11 10:53:51 EST (Tue, 11 Dec 2007)
@@ -97,11 +97,11 @@
     void write_attributes(std::ostream& s_out)
     { // group_element id and clip-path.
       if(id_name.size() != 0)
- {
+ { // Example: id="imageBackground"
         s_out << " id=\"" << id_name << "\""; // Prefix with space.
       }
       if(clip_name.size() != 0)
- {
+ { // Example: clip-path="url(#plot_window)"
         s_out << " clip-path=\"url(#" << clip_name << ")\""; // Prefix with space.
       }
       // Inherited classes add other references, 5.3.1, like color, fill, stroke, gradients...
@@ -370,18 +370,31 @@
     int size; // " font-size = 12"
     // http://www.w3.org/TR/SVG/text.html#CharactersAndGlyphs
     std::string font; // font-family: "Arial" | "Times New Roman" | "Verdana" | "Lucida Sans Unicode"
- std::string style; // font-style: normal | bold | italic | oblique
+ // "sans", "serif", "times"
+ std::string style_; // font-style: normal | bold | italic | oblique
     std::string weight; // font-weight: normal | bold | bolder | lighter | 100 | 200 .. 900
     std::string stretch; // font-stretch: normal | wider | narrower ...
     std::string decoration; // // "underline" | "overline" | "line-through"
     align_style align; // left_align, right_align, center_align
     int rotate; // horizontal, upward, downward, upsidedown
-
     // Example:
     // <text x="250" y="219.5" text-anchor="middle" font-family="verdana" font-size="12">0 </text>
 
+ text_style style_info_;
+
   public:
     // Set and get member functions.
+
+ text_style& style()
+ {
+ return style_info_;
+ }
+
+ const text_style& style() const
+ {
+ return style_info_;
+ }
+
     void font_alignment(align_style a)
     { // left_align, right_align, center_align
       align = a;
@@ -404,12 +417,12 @@
 
     void font_style(const std::string& s)
     {
- style = s;
+ style_ = s;
     }
 
     const std::string& font_style() const
     {
- return style;
+ return style_;
     }
 
     void font_weight(const std::string& s)
@@ -499,12 +512,12 @@
       const std::string& style = "", const std::string& weight = "",
       const std::string& stretch = "", const std::string& decoration = "",
       align_style align = center_align, int rotate = horizontal)
- :
+ : // Constructor.
     x_coord(x), y_coord(y),
       txt(text),
       size(size),
       font(font),
- style(style), weight(weight), stretch(stretch), decoration(decoration),
+ style_(style), weight(weight), stretch(stretch), decoration(decoration),
       align(align), rotate(rotate)
     { // text_element default constructor, defines defaults for all private members.
     }
@@ -545,9 +558,9 @@
       {
         rhs << " font-family=\"" << font << "\"";
       }
- if (style.size() != 0)
+ if (style_.size() != 0)
       {
- rhs << " font-style=\"" << style << "\"";
+ rhs << " font-style=\"" << style_ << "\"";
       }
       if (weight.size() != 0)
       {
@@ -561,11 +574,7 @@
       {
       rhs << " font-decoration=\"" << decoration << "\"";
       }
- if(size == 0)
- { // Use a default font size of 12 if none specified.
- rhs << " font-size=\"12\">";
- }
- else
+ if(size != 0)
       {
         rhs << " font-size=\"" << size << "\">";
       }
@@ -575,6 +584,7 @@
 
   }; // class text_element
 
+
   class clip_path_element: public svg_element
   { // The clipping path restricts the region to which paint can be applied.
     // 14.3 Clipping paths http://www.w3.org/TR/SVG/masking.html#ClipPathProperty
@@ -892,8 +902,6 @@
     { // TODO why is the default fill(true)?
     }
 
-
-
     // Note 1: return of path_element& permits chaining calls like
     // my_path.M(3, 3).l(150, 150).l(200, 200)...;
 
@@ -1310,11 +1318,11 @@
 
     void write(std::ostream& os)
     {
- // WOuld be nice to avoid useless <g id="yMinorGrid"></g>
+ // Would be nice to avoid useless <g id="yMinorGrid"></g>
       // TODO but would this mean that useful style is lost?
 
       os << "<g"; // Do NOT need space if convention is to start following item with space.
- write_attributes(os); // id="background"
+ write_attributes(os); // id="background" (or clip_path)
       style_info.write(os); // stroke="rgb(0,0,0)"
       os << ">" ;
       for(unsigned int i = 0; i < children.size(); ++i)

Modified: sandbox/SOC/2007/visualization/boost/svg_plot/svg.hpp
==============================================================================
--- sandbox/SOC/2007/visualization/boost/svg_plot/svg.hpp (original)
+++ sandbox/SOC/2007/visualization/boost/svg_plot/svg.hpp 2007-12-11 10:53:51 EST (Tue, 11 Dec 2007)
@@ -24,6 +24,18 @@
 // SVG stands for Scalable Vector Graphics,
 // an XML grammar for stylable graphics, usable as an XML namespace.
 
+// http://www.adobe.com/svg/basics/intro.html SVG Workflow on optimising SVG
+// Gzip compression - can give files that are 1/10th size of gif or jpeg.
+// Use default values whenever possible rather than defining all attributes and properties explicitly.
+// Take advantage of the path data compaction facilities — use relative coordinates;
+// use h and v for horizontal and vertical lines;
+// use s or t for cubic and quadratic Bezier segments whenever possible;
+// eliminate extraneous white space and separators.
+// Use symbols if the same graphic appears multiple times in the document.
+//Use CSS property inheritance and selectors to consolidate commonly used properties into named styles
+// or to assign the properties to a parent <g> element.
+//Use filter effects to help construct graphics via client-side graphics operations.
+
 namespace boost
 {
 namespace svg
@@ -53,8 +65,6 @@
 
 
 class svg;
-// TODO is it wise to have a class and a namespace with the same name?
-// No problems caused by this noted so far.
 
 // See svg_fwd.hpp for forward declarations.
 // Public member functions:
@@ -127,21 +137,57 @@
   // ---------------------------------------------------------
   void write_header(std::ostream& s_out)
   {
- s_out << "<?xml version=\"1.0\" standalone=\"no\"?>"
+ s_out << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"
       << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" "
       << "\"http://www.w3.org/graphics/svg/1.1/dtd/svg11.dtd\">"
       << std::endl;
     // TODO IE6 with updates does not recognise this DOCTYPE, but displays OK.
     // http://jwatt.org/svg/authoring/#namespace-binding recommends NO DOCTYPE!
+
+
+ //s_out << "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
+ // "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20000303 Stylable//EN\"
+ // \"http://www.w3.org/TR/2000/03/WD-SVG-20000303/DTD/svg-20000303-stylable.dtd\">\n"
+ // This IS out of date? version 1.0 TR 2000, but the Adobe SVG viewer complains
+ // if it is missing - but ignore.
+ // But Firefox says document does not contain style.
+ // http://www.adobe.com/svg/basics/getstarted.html
+
+ // Inkscape uses encoding=\"UTF-8\" Unicode
+ // (encoding=\"iso-8859-1\" == Latin now obselete)
+
+ // example of style command:
+ // style="font-size:20px;font-weight:bold;text-decoration: line-through;fill:aqua"
+
+ // font-family:Arial Narrow
+
+ // INscape uses: xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
   }
 
   void write_css(std::ostream& s_out)
   { // CSS (Cascading Style Sheet)
     if (css.size() != 0) // css != ""
     { // TODO confirm that this isn't useful if css is "".
+ // [CDATA[ ... ]] enclosing the style information
+ // is a standard XML construct for hiding information
+ // necessary since CSS style sheets can include characters,
+ // such as ">", which conflict with XML parsers.
       s_out << "<defs><style type=\"text/css\"><![CDATA[" << css
         << "]]></style></defs>" << std::endl;
- // Example: <defs><style type="text/css"><![CDATA[]]></style></defs>
+ // CSS inline style can be declared within a style attribute in SVG
+ // by specifying a semicolon-separated list of property declarations,
+ // where each property declaration has the form "name: value".
+ // For example a style: style="fill:red; stroke:blue; stroke-width:3"
+ // class=
+ // Multiple class names must be separated by whitespace.
+
+ // Example: <defs><style type="text/css"><![CDATA[]]>
+ // .axes { fill:none;stroke:#333333;stroke-width:1.6 }
+ // .title{ font-size:20px;font-weight:bold;font-style:italic;fill:magenta }
+ // .legend_header{ font-size:16px;font-weight:bold;fill:darkblue;text-anchor:middle }
+ // .legend_item{ font-size:16px;font-weight:normal;fill:blue }
+ // .x_axis_value{ font-size:12px;font-weight:normal;fill:black }
+ // </style></defs>
     }
   }
 
@@ -180,12 +226,13 @@
     distribution_("permits"), // permits, requires, or prohibits.
     attribution_("requires"),
     commercialuse_("permits"),
- coord_precision_(3) // enough for 1 in 1000 resolution to suit use.
+ coord_precision_(3) // enough for 1 in 1000 resolution to suit small image use.
   { // Default constructor.
   }
 
   svg(const svg& rhs) : x_size_(rhs.x_size_), y_size_(rhs.y_size_)
   { // Defined image size copy constructor.
+ // TODO Other member data items are NOT copied. OK?
   }
 
   // Set & get functions for x_size_ and y_size_
@@ -266,13 +313,19 @@
   { // Write whole .svg 'file' contents to stream (perhaps a file).
     write_header(s_out); // "<?xml version=...
     // write svg document, begin <svg tag.
+ // <svg xml:space="preserve" width="5.5in" height=".5in">
+
     s_out << "<svg width=\"" << x_size_ << "\" height =\"" << y_size_
       << "\" version=\"1.1\"" // http://www.w3.org/TR/SVG11/
       // 1.2 draft specification at http://www.w3.org/TR/SVG12/
       << " xmlns=\"http://www.w3.org/2000/svg\"\n"
       // xml namespace containing svg shapes rect, circle...
       // so can write rect or circle avoiding need for qualification svg:rect, svg:circle...
+ // This site isn't visited, but if missing Firefox, at least, will fail to render.
          " xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
+ // tells that elements and attributes which are prefixed by "xlink:"
+ // are a part of the xlink specification http://www.w3.org/1999/xlink.
+ // Need to use xlink:href to refer to xlink.
          " xmlns:ev=\"http://www.w3.org/2001/xml-events\">\n"
       << std::endl;
     // Bind the required namespaces, see http://jwatt.org/svg/authoring/#namespace-binding

Modified: sandbox/SOC/2007/visualization/boost/svg_plot/svg_2d_plot.hpp
==============================================================================
--- sandbox/SOC/2007/visualization/boost/svg_plot/svg_2d_plot.hpp (original)
+++ sandbox/SOC/2007/visualization/boost/svg_plot/svg_2d_plot.hpp 2007-12-11 10:53:51 EST (Tue, 11 Dec 2007)
@@ -86,7 +86,7 @@
   // multimap sorts and ensures that lines joining data points
   // are unaffected by the order in which data is presented.
   // (For 1-D a vector of doubles can be used).
-
+
   std::string title;
   plot_point_style point_style;
   plot_line_style line_style;
@@ -97,7 +97,7 @@
     const plot_point_style& point,
     const plot_line_style& line)
     :
- title(title),
+ title(title),
     point_style(point),
     line_style(line)
   { // Constructor.
@@ -171,18 +171,20 @@
   // text width is effectively the boldness of the font.
   // 0 is default, 1 is bolder, 2 very bold...
   // TODO SVG has also a not yet implemented boldness.
- double title_font_width_;
+ double title_font_width_;
   double legend_font_width_;
   double legend_width_; // width of legend box in pixels.
- double legend_x1_; // Left of legend box. (Optionally set by legend_position).
+ double legend_height_; // height of legend box in pixels.
+ double legend_x1_; // Left of legend box. (Optionally set by legend_top_left).
   double legend_y1_; // Top of legend box.
   // Size of legend box is controlled by its contents,
   // but may be helpful to store bottom right coordinates.
   // legend_bottom_right() gives access.
   double legend_x2_; // right of legend box.
   double legend_y2_; // bottom of legend box.
- double x_label_width_; // Used for
- double y_label_width_; // TODO used for axis width too for now. OK?
+ size_t legend_longest_; // longest string in legend box.
+ double x_label_width_; // Used for
+ double x_axis_width_; // X-axis horizontal line width. set/get by x_axis_width()
   double x_major_tick_length_; // pixels.
   double x_major_tick_width_; // pixels.
   double x_minor_tick_length_; // pixels.
@@ -200,7 +202,9 @@
   double y_max; // maximum y value (Cartesian units).
   double y_major_interval_; // y_major_interval_ is the stride or interval for major y ticks.
   double y_minor_interval_; // y_minor_interval_ is the stride or interval for minor y ticks.
+ double y_label_width_; // TODO used for axis width too for now. OK?
   double y_axis; // Y-axis (x = 0) transformed into SVG coordinates.
+ double y_axis_width_; // Y-axis vertical line width. set/get by y_axis_width()
   double y_major_tick_length_; // pixels.
   double y_major_tick_width_; // pixels.
   double y_minor_tick_length_; // pixels.
@@ -242,6 +246,7 @@
   bool use_y_axis_lines_; // Draw a vertical Y-axis line.
   bool use_line; // get/set by line_on(bool); // Not really useful for 1-D,
   // TODO but needs Boost-Parameter removed to do properly.
+ bool strip_e0s_;
 
   // Where we will be storing the data points (series) for transformation.
   std::vector<svg_2d_plot_series> series; // Defined above.
@@ -257,46 +262,50 @@
 public: // of class svg_2d_plot: public detail::axis_plot_frame<svg_2d_plot>
 
   svg_2d_plot() // Constructor, including all the very many default plot options.
- :
+ :
     // TODO check that *all* options are initialized here.
     // See documentation for default settings rationale.
 
     title_info(0, 0, "Plot of data", 16, "Verdana", "", "", "", "", center_align, horizontal),
     title_font_width_(1), // text width is effectively the boldness of the font.
     legend_width_(200), // width of legend box (pixels)
- legend_header_(0, 0, "", 14, "Verdana", "", "", "", "", center_align, horizontal),
+ legend_header_(0, 0, "", 14, "Verdana", "italic", "", "bold", "", center_align, horizontal),
     legend_font_width_(0.5),
- x_label_info(0, 0, "X Axis", 16, "Verdana", "", "", "", "", center_align, horizontal),
- x_label_value(0, 0, "", 10, "Verdana", "", "", "", "", center_align, horizontal),
+ x_label_info(0, 0, "X Axis", 14, "Verdana", "", "bold", "", "", center_align, horizontal),
+ x_units_info(0, 0, "(units)", 14, "Verdana", "", "", "", "", center_align, horizontal),
+ x_label_value(0, 0, "", 12, "Verdana", "", "", "", "", center_align, horizontal),
     // TODO use this and provide way to set'n'get separately.
- x_label_width_(0.5),
- y_label_info(0, 0, "Y Axis", 14, "Verdana", "", "", "", "", center_align, upward),
+ x_label_width_(2),
+ x_axis_width_(2),
+ y_label_info(0, 0, "Y Axis", 14, "Verdana", "", "bold", "", "", center_align, upward),
+ y_units_info(0, 0, "(units)", 14, "Verdana", "", "", "", "", center_align, upward),
     y_label_value(0, 0, "", 12, "Verdana", "", "", "", "", center_align, upward),
- y_label_width_(0.5),
+ y_label_width_(5),
+ y_axis_width_(2), // vertical line.
     x_label_rotation_(horizontal),
     y_label_rotation_(horizontal),
- x_units_info(0, 0, "(units)", 14, "Verdana", "", "", "", "", center_align, horizontal),
- y_units_info(0, 0, "(units)", 14, "Verdana", "", "", "", "", center_align, upward),
     // Plot may look odd if font and size of label & units are different!
     // y_units_info(0, 0, "(units)", 11, "Times New Roman", "italic", "bold", "wider", "underline", right_align, upsidedown),
     // shows some values that might be useful if svg browsers are fully implemented
     // to support font modification to text characters.
+ // italic and bold seem the only ones working at present.
     x_value_precision_(3), // precision for tick value labels, usually 3 will suffice.
     x_value_ioflags_(std::ios::dec), // Provides a way of controlling scientific format, etc.
     y_value_precision_(3), // precision for tick value labels, usually 3 will suffice.
     y_value_ioflags_(std::ios::dec), // Provides a way of controlling scientific format, etc.
- // Note that ALL the flags are set, overwriting the defaults.
- text_margin_(2.), // for text, as a multiplier of the font size.
- border_margin_(5), // Prevent plot window box begin right on edge?
- // plot_x1, x2, y1, 2 are set in calculate_plot_window
- border_width_(2), // width of border to plot window and legend box.
- legend_x1_(-1), legend_x2_(-1),legend_y1_(-1),legend_y2_(-1), // Indicates not yet set.
- x_min(-10), x_max(10), // so plots from -10 to +10
+ // Note that ALL the flags are set, overwriting any defaults, so std::dec is wise.
+ text_margin_(1.5), // for axis label text, as a multiplier of the font size.
+ border_margin_(10), // Prevent plot window box begin right on edge,
+ border_width_(20), // width of any border to plot window and legend box.
+ // less than half the font size of label value will result in clipping.
+ // plot_x1, x2, y1, 2 are set in calculate_plot_window
+ legend_x1_(-1), legend_x2_(-1),legend_y1_(-1),legend_y2_(-1), // -1 Indicates not yet set.
+ x_min(-10), x_max(10), // so plots range from -10 to +10
     y_min(-10), y_max(10),
     x_major_interval_(2), // x stride between major ticks & value label.
     y_major_interval_(2), // y stride
     // Ticks on axes.
- x_num_minor_ticks_(2), // suits
+ x_num_minor_ticks_(4), // suits
     y_num_minor_ticks_(4), // suits: major 0, minor 2, 4, 6, 8, major 10
     x_major_tick_length_(10.), // If both up and down, total is twice this.
     x_minor_tick_length_(5.),
@@ -311,6 +320,7 @@
     x_minor_grid_width_(0.5),
     y_major_grid_width_(1.),
     y_minor_grid_width_(0.5),
+ // Use by transform Cartesian to SVG.
     x_scale(1.), x_shift(0.),
     y_scale(1.), y_shift(0.),
     x_minor_interval_(0), // These are calculated from x & y_num_minor_ticks_
@@ -319,6 +329,7 @@
     plot_window_clip("plot_window"), // for <clipPath id="plot_window" ...
 
     // Boolean options.
+ strip_e0s_(false),
     use_down_ticks(true), // On X-axis.
     use_up_ticks(false), // external ticks only.
     //use_x_ticks(false), // = use_up_ticks || use_down_ticks
@@ -363,27 +374,25 @@
 
     // Tick length etc is now set above in the constructor, but width & color here.
     image.get_g_element(PLOT_BACKGROUND).style().fill_color(white);
- image.get_g_element(PLOT_BACKGROUND).style().stroke_color(grey); // TODO test only ?
- image.get_g_element(PLOT_BACKGROUND).style().stroke_width(1); //
+ image.get_g_element(PLOT_BACKGROUND).style().stroke_color(linen); // TODO test only ?
+ image.get_g_element(PLOT_BACKGROUND).style().stroke_width(0.5); //
     image.get_g_element(PLOT_WINDOW_BACKGROUND).style().fill_color(white);
- image.get_g_element(PLOT_WINDOW_BACKGROUND).style().stroke_width(2).stroke_color(silver);
+ image.get_g_element(PLOT_WINDOW_BACKGROUND).style().stroke_width(1).stroke_color(lightyellow);
     image.get_g_element(PLOT_LIMIT_POINTS).style().stroke_color(lightslategray).fill_color(antiquewhite);
- image.get_g_element(PLOT_X_AXIS).style().stroke_color(black).stroke_width(x_label_width_);
- image.get_g_element(PLOT_Y_AXIS).style().stroke_color(black).stroke_width(y_label_width_);
- image.get_g_element(PLOT_X_LABEL).style().stroke_color(black).stroke_width(x_label_width_);
- image.get_g_element(PLOT_Y_LABEL).style().stroke_color(black).stroke_width(y_label_width_);
- image.get_g_element(PLOT_VALUE_LABELS).style().stroke_color(black).stroke_width(x_label_width_); // text
- // TODO?? Y label width?
- image.get_g_element(PLOT_LEGEND_TEXT).style().stroke_width(legend_font_width_);
- image.get_g_element(PLOT_TITLE).style().stroke_width(title_font_width_); //
- image.get_g_element(PLOT_TITLE).style().stroke_color(black);
- // If color is not set, then get a very 'thin' font and width has no effect!
+ image.get_g_element(PLOT_X_AXIS).style().stroke_color(red).stroke_width(x_axis_width_);
+ image.get_g_element(PLOT_Y_AXIS).style().stroke_color(blue).stroke_width(y_axis_width_);
+ image.get_g_element(PLOT_X_LABEL).style().fill_color(black);
+ image.get_g_element(PLOT_Y_LABEL).style().fill_color(black);
+ image.get_g_element(PLOT_VALUE_LABELS).style().fill_color(black); // text
+ image.get_g_element(PLOT_LEGEND_TEXT).style().fill_color(blue);
+ image.get_g_element(PLOT_TITLE).style().fill_color(black).stroke_on(false);
+ // If stroke color is not set, then get a very 'thin' font and width has no effect.
+ // Firefox text is rather thin compared to IE.
 
     // Note that widths are stored in member data *and* copied here.
     // Not sure if this is wise but ...
 
     // Ticks
- // TODO allow color of ticks independent of axes color?
     if(use_up_ticks || use_down_ticks)
     {
       image.get_g_element(PLOT_X_MAJOR_TICKS).style().stroke_width(x_major_tick_width_).stroke_color(black);
@@ -395,36 +404,36 @@
       image.get_g_element(PLOT_Y_MINOR_TICKS).style().stroke_width(y_minor_tick_width_).stroke_color(black);
     }
     // Grids.
- // TODO these may not be needed here - they MUST be set at call time in case use_x_major_grid_ has changed.
- if(use_x_major_grid_)
- { // pale blue.
- image.get_g_element(PLOT_X_MAJOR_GRID).style().stroke_width(x_major_grid_width_).stroke_color(svg_color(200, 220, 255));
- }
- if(use_x_minor_grid_)
- {
- image.get_g_element(PLOT_X_MINOR_GRID).style().stroke_width(x_minor_grid_width_).stroke_color(svg_color(200, 220, 255));
- }
- if(use_y_major_grid_)
- {
- image.get_g_element(PLOT_Y_MAJOR_GRID).style().stroke_width(y_major_grid_width_).stroke_color(svg_color(200, 220, 255));
- }
- if(use_y_minor_grid_)
- {
- image.get_g_element(PLOT_Y_MINOR_GRID).style().stroke_width(y_minor_grid_width_).stroke_color(svg_color(200, 220, 255));
- }
+ //// Note: may not be needed here - they MUST be set at call time in case use_x_major_grid_ has changed.
+ //if(use_x_major_grid_)
+ //{ // pale blue.
+ // image.get_g_element(PLOT_X_MAJOR_GRID).style().stroke_width(x_major_grid_width_).stroke_color(svg_color(200, 220, 255));
+ //}
+ //if(use_x_minor_grid_)
+ //{
+ // image.get_g_element(PLOT_X_MINOR_GRID).style().stroke_width(x_minor_grid_width_).stroke_color(svg_color(200, 220, 255));
+ //}
+ //if(use_y_major_grid_)
+ //{
+ // image.get_g_element(PLOT_Y_MAJOR_GRID).style().stroke_width(y_major_grid_width_).stroke_color(svg_color(200, 220, 255));
+ //}
+ //if(use_y_minor_grid_)
+ //{
+ // image.get_g_element(PLOT_Y_MINOR_GRID).style().stroke_width(y_minor_grid_width_).stroke_color(svg_color(200, 220, 255));
+ //}
 
- // NO need to call these even if the default is not to be used.
- // TODO are these needed?
     // Default color for grid.
       image.get_g_element(PLOT_X_MAJOR_GRID).style().stroke_width(x_major_grid_width_).stroke_color(svg_color(200, 220, 255));
       image.get_g_element(PLOT_X_MINOR_GRID).style().stroke_width(x_minor_grid_width_).stroke_color(svg_color(200, 220, 255));
       image.get_g_element(PLOT_Y_MAJOR_GRID).style().stroke_width(y_major_grid_width_).stroke_color(svg_color(200, 220, 255));
       image.get_g_element(PLOT_Y_MINOR_GRID).style().stroke_width(y_minor_grid_width_).stroke_color(svg_color(200, 220, 255));
+ image.get_g_element(PLOT_DATA_LINES).style().stroke_width(2);
+
   } // svg_2d_plot() default constructor.
 
 private:
   // svg_2d_plot Member Functions.
-
+
   void set_ids()
   { // document ids for use in <g id = "PLOT_TITLE".../>
     for(int i = 0; i < detail::SVG_PLOT_DOC_CHILDREN; ++i)
@@ -453,11 +462,14 @@
     // this ensures that data points and lines (and anything else)
     // outside this window is NOT drawn.
     // Start by assuming we can use all the svg image.
+ // TODO Should this be reduced by width of any image border?
     plot_x1 = 0; // left
     plot_y1 = 0; // top
     plot_x2 = image.x_size(); // right
     plot_y2 = image.y_size(); // bottom
 
+ calculate_legend_box();
+
     if(use_x_label)
     { // Leave space at bottom for X axis label.
       plot_y2 -= x_label_info.font_size() * text_margin_;
@@ -469,88 +481,97 @@
     if(use_title)
     { // Leave space at top for title.
       // TODO what if want to put title at bottom?
- plot_y1 += title_font_size() * (text_margin_ +1);
+ plot_y1 += title_font_size() * (text_margin_ + 1);
     }
     if(use_plot_window)
     { // Reduce to allow for legend, axes ticks to be on or outside plot_window.
       // Give the plot window a border (set with plot_border_width(double)).
- // Needed to allow any window border rectangle to show OK.
- plot_x1 += plot_border_width(); // pixels.
- plot_x2 -= plot_border_width();
- plot_y1 += plot_border_width();
- plot_y2 -= plot_border_width();
+ // Needed to allow any plot window border rectangle to show OK.
+ // border_margin is to prevent it being right on the image border,
+ // perhaps covered by any rectangle making image border.
+ plot_x1 += plot_border_width() + border_margin(); // pixels.
+ plot_x2 -= plot_border_width() + border_margin();
+ plot_y1 += plot_border_width() + border_margin();
+ plot_y2 -= plot_border_width() + border_margin();
+ // Also need a >half font to allow the value label on any max major tick to avoid clipping.
       // Even after reading http://www.w3.org/TR/SVG/fonts.html, unclear how to
- // determine the width of digits, so an arbitrary width height ratio is used:
- const double wh = 0.7; // width compared to font height (assume size is this).
- static const double sin45 = 0.707;
- if(use_legend)
- { // Space for legend at right.
- // TODO what if want legend elsewhere?
+ // determine the width of digits, so an arbitrary width height ratio wh is used:
+ const double wh = 0.7; // width compared to font height.
+ static const double sin45 = 0.707; // Use if axis value labels are sloping.
+ if(use_legend
+ && (legend_x1_ == -1) ) // Legend box position NOT been set by legend_top_left.
+ { // Leave space for legend at right of plot window.
         plot_x2 -= legend_width_; // legend box width.
- // TODO size could depend on font_size & length of text??? Sounds tricky.
       }
+ // value_precision is
       if (use_y_major_labels && use_y_ticks_on_plot_window_)
       { // Move plot window right to make space for value labels.
         // We would really like to know the length of the longest value label here!
         // Might convert the max and then use its .length()?
- int l = (y_value_precision_ + 2);
- if(y_value_ioflags_ & std::ios::scientific)
- { // ALso need space for e, sign & 3 exponent digits = 5)
- l += 5;
+ int l = (y_value_precision_ + 1 + 1); // sign & decimal point.
+ if((y_value_ioflags_ & std::ios::scientific) == std::ios::scientific)
+ { // precision is number of decimal places in the fractional part (default 6).
+ l += 5; // Also need space for e, sign & 3 exponent digits = 5)
          }
- else if(y_value_ioflags_ & std::ios::fixed)
- { // Need space for decimal point & sign & at least 1 more digit)
- l += 3;
+ else if((y_value_ioflags_ & std::ios::fixed) == std::ios::fixed)
+ { // precision is
+ l += 2; // Need space for decimal point & at least 1 more digit)
+ }
+ else
+ { // Default neither fixed nor scientific, no leading or trailing zero(s).
+ // allowing sign and decimal point should probably be enough,
+ // but only a check of the actual values will be accurate. TODO?
          }
         if (y_label_rotation_ == horizontal)
         { // Move edge right to give space for y_value_precision_ digits.
           plot_x1 += y_label_value.font_size() * (l * wh);
         }
         else if((y_label_rotation_ == upward) || (y_label_rotation_ == downward))
- { // Only need one char width.
+ { // Only need one char width from Y-axis label.
           plot_x1 += y_label_value.font_size() * 1.5;
         }
         else
- { // assume some slope 45? So diagonally down from tick,
+ { // Assume some slope 45, so diagonally down from tick,
           // and takes a bit less room.
           plot_x1 += y_label_value.font_size() * l * wh * sin45;
         }
       }
       if (use_x_major_labels && use_x_ticks_on_plot_window_)
- { // Move bottom up to give space for x value labels
- // x_value_precision_ digits.
- // (perhaps + 1 for negative sign?).
+ { // Move bottom of plot window up to give space for x value labels.
+ // x_value_precision_ digits etc.
         double l = x_value_precision_ + 1 + 1; // sign & decimal point.
- if (x_value_ioflags_ == std::ios::scientific)
- { // space for e+000
- l += 5;
- }
- else if(y_value_ioflags_ & std::ios::fixed)
- { // Need space for decimal point & sign & at least 1 more digit)
- l += 3;
- }
-
- if ((x_label_rotation_ == upward) || (x_label_rotation_ == downward))
- { // need
- l += 2; // extra space at top and bottom?
- }
- else if(x_label_rotation_ != horizontal)
+ if(x_label_rotation_ == horizontal)
         { // Only 1 char height & 1 space needed if horizontal.
           l = 2;
+ }
+ else
+ { // will need more than 2
+ //l += 1; // extra space at top and bottom?
+ if ((x_value_ioflags_ & std::ios::scientific) == std::ios::scientific)
+ { // space for "e+000"
+ l += 5;
+ }
+ else if((x_value_ioflags_ & std::ios::fixed) == std::ios::fixed)
+ { // Need space for decimal point & sign & at least 1 more digit)
+ l += 3;
+ }
+ if ((x_label_rotation_ == upward) || (x_label_rotation_ == downward))
+ { // need space for longest.
+ }
+ else
+ { // Assume some slope, say 45 sin(45) = 0.707.
+ l *= sin45;
+ }
         }
- else
- { // assume some slope, say 45 sin(45) = 0.707?
- l *= 0.707;
- }
- plot_y2 -= x_label_value.font_size() * l;
+ plot_y2 -= x_label_value.font_size() * l * wh; // Move up.
       }
       if(use_left_ticks)
- { // Reduce plot to give space for biggest of any external left ticks.
+ { // Start left of plot to right to give space for biggest of any external left ticks.
         plot_x1 += (std::max)(y_major_tick_length_, y_minor_tick_length_); // Avoid macro max trap!
           // TODO y_major_tick_length_ > y_minor_tick_length_ ? y_major_tick_length_ : y_minor_tick_length_;
       }
       if(use_down_ticks)
- { // Reduce plot to give space for any external down ticks.
+ { // Start bottom of plot higher to give space for any external down ticks.
         plot_y2 -=(std::max)(x_major_tick_length_, x_minor_tick_length_);
           //x_major_tick_length_ > x_minor_tick_length_ ? x_major_tick_length_ : x_minor_tick_length_;
       }
@@ -560,6 +581,7 @@
     } // use_plot_window
   } // calculate_plot_window
 
+
   void draw_y_minor_ticks(double value, path_element& tick_path, path_element& grid_path)
   {
     double x1(0.);
@@ -576,7 +598,7 @@
         // x2 -= title_info.font_size() * text_margin_;
         //}
         if(use_y_label)
- {
+ {
           x1 += y_label_info.font_size() * text_margin_;
           x2 -= y_label_info.font_size() * text_margin_;
         }
@@ -619,7 +641,7 @@
     }
     else
     {// Do nothing? warn?
- std::cout << "y minor tick OUTside " << x1 << ' ' << y1 << ' ' << x2 << std::endl;
+ // std::cout << "y minor tick OUTside " << x1 << ' ' << y1 << ' ' << x2 << std::endl;
 
     }
   } // void draw_y_minor_ticks
@@ -655,7 +677,7 @@
       }
       grid_path.M(x1, y1).L(x2, y1);
     } // use_y_major_grid_
-
+
     if((y1 <= plot_y2) && (y1 >= plot_y1))
     { // Make sure that we are drawing inside the allowed window.
       double y_tick_length = y_major_tick_length_;
@@ -730,12 +752,12 @@
       { // ! use_y_ticks_on_plot_window_Internal - value labels close to left of vertical Y-axis.
         if ((value != 0) && use_x_axis_lines_)
         { // Avoid a zero ON the Y-axis as it would be cut through by the horizontal X-axis line.
- y += y_label_value.font_size() / 2;
- image.get_g_element(detail::PLOT_VALUE_LABELS).text(x1,
+ y += y_label_value.font_size() / 2;
+ image.get_g_element(detail::PLOT_VALUE_LABELS).text(x1,
             y, // Just shift down half a digit to center value digits on tick.
             label.str(), y_label_value.font_size(), y_label_value.font_family(), "", "", "", "",
             center_align, // on the tick ???
- y_label_rotation_);
+ y_label_rotation_);
         }
       }
     } // if(use_y_major_labels)
@@ -748,7 +770,12 @@
     y_axis = x1; // in SVG coordinates.
     if(use_y_axis_lines_)
     { // Draw the vertical Y-axis line (at cartesian x = 0).
- image.get_g_element(detail::PLOT_Y_AXIS).line(x1, plot_y1, x1, plot_y2);
+ double ybottom = plot_y2;
+ if (use_down_ticks)
+ { // Extend the vertical line down in lieu of a tick.
+ ybottom += (std::max)(x_minor_tick_length_, x_major_tick_length_);
+ }
+ image.get_g_element(detail::PLOT_Y_AXIS).line(x1, plot_y1, x1, ybottom);
     // <g id="yAxis" stroke="rgb(0,0,0)"><line x1="70.5" y1="53" x2="70.5" y2="357"/>
     }
     // Access the paths for the ticks & grids, ready for additions.
@@ -760,7 +787,8 @@
     if(use_y_ticks_on_plot_window_)
     { // TODO confirm that labels allow space.
       // Was y_external style - so both labels (and ticks) are OUTSIDE the plot window.
- image.get_g_element(detail::PLOT_Y_AXIS).line(plot_y1, x_axis, plot_x2, x_axis);
+ //image.get_g_element(detail::PLOT_Y_AXIS).line(plot_y1, x_axis, plot_x2, x_axis);
+ // TODO this looks rubbish.
     }
 
     // y_minor_jump is the interval between minor ticks.
@@ -770,9 +798,11 @@
     // But may still fail if a ls or few bits out? Seems to fail for y = 100, for example.
 
     // Draw the ticks on the positive side.
- for(double i = 0; i <= y_max; i += y_major_interval_)
+ for(double y = 0; y <= y_max; y += y_major_interval_)
     {
- for(double j = i + y_minor_jump; j < i + y_major_interval_; j += y_minor_jump)
+ for(double j = y + y_minor_jump;
+ j < (y + y_major_interval_) * (1. - 2 * std::numeric_limits<double>::epsilon());
+ j += y_minor_jump)
       { // Draw minor ticks.
         // This will output 'orphaned' minor ticks that are beyond the plot window,
         // if the last major tick does not coincide with the plot window.
@@ -780,19 +810,35 @@
         // There might be 9 of them,
         // if you have the common 9 minor tick between major ticks!
         // TODO this seems ugly - as does the negative ones below.
- draw_y_minor_ticks(j, minor_tick_path, minor_grid_path);
+ if (j != 0. || ! use_x_axis_lines_)
+ { // Avoid a major tick at y == 0 where there *is* a horizontal X-axis line.
+ // (won't be X-axis line for 1-D where the zero tick is always wanted).
+ draw_y_minor_ticks(j, minor_tick_path, minor_grid_path);
+ }
+ }
+ if ((y != 0. || ! use_x_axis_lines_) || use_y_ticks_on_plot_window_)
+ { // Avoid a major tick at y == 0 where there *is* a horizontal X-axis line.
+ // (won't be X-axis line for 1-D where the zero tick is always wanted).
+ draw_y_major_ticks(y, major_tick_path, major_grid_path);
       }
- draw_y_major_ticks(i, major_tick_path, major_grid_path);
     }
 
     // Draw the ticks on the negative side.
- for(double i = 0; i >= y_min; i -= y_major_interval_)
+ for(double y = 0; y >= y_min; y -= y_major_interval_)
     {
- for(double j=i; j > i-y_major_interval_; j-= y_major_interval_ / (y_num_minor_ticks_ + 1))
+ for(double j=y; j > y-y_major_interval_; j-= y_major_interval_ / (y_num_minor_ticks_ + 1))
       { // Draw minor ticks.
- draw_y_minor_ticks(j, minor_tick_path, minor_grid_path);
+ if ((j != 0. || ! use_x_axis_lines_) || use_y_ticks_on_plot_window_)
+ { // Avoid a major tick at y == 0 where there *is* a horizontal X-axis line.
+ // (won't be X-axis line for 1-D where the zero tick is always wanted).
+ draw_y_minor_ticks(j, minor_tick_path, minor_grid_path);
+ }
+ }
+ if ((y != 0. || ! use_x_axis_lines_) || use_y_ticks_on_plot_window_)
+ { // Avoid a major tick at y == 0 where there *is* a horizontal X-axis line.
+ // (won't be X-axis line for 1-D where the zero tick is always wanted).
+ draw_y_major_ticks(y, major_tick_path, major_grid_path);
       }
- draw_y_major_ticks(i, major_tick_path, major_grid_path);
     }
   } // draw_y_axis
 
@@ -841,7 +887,7 @@
     {
       std::multimap<double, double>::const_iterator j = series.series.begin();
 
- // If we have to fill the area under the plot,
+ // If we have to fill the area under the plot,
       // we first have to move from the X-axis (y = 0) to the first point,
       // and again at the end after the last point.
       prev_x = (*j).first;
@@ -894,8 +940,8 @@
     g_ptr.style().stroke_color(series.line_style.color);
     path_element& path = g_ptr.path();
 
- std::pair<double, double> n;
- std::pair<double, double> n_minus_1;
+ std::pair<double, double> n; // current point.
+ std::pair<double, double> n_minus_1; // penultimate.
     std::pair<double, double> n_minus_2;
     std::pair<double, double> fwd_vtr;
     std::pair<double, double> back_vtr;
@@ -911,39 +957,51 @@
     }
 
     if(series.series.size() > 2)
- { // Need >= 3 for a curve, of course.
+ { // Need >= 3 for a cubic curve (start point, 2 control points, and end point).
       std::multimap<double, double>::const_iterator iter = series.series.begin();
-
- n_minus_1 = *(iter++);
- n = *(iter++);
+ n_minus_1 = *(iter++); // begin()
       transform_pair(n_minus_1);
+ n = *(iter++); // middle
       transform_pair(n);
- path.M(n_minus_1.first, n_minus_1.second);
+ path.M(n_minus_1.first, n_minus_1.second); // move m_minus_1, the 1st data point.
+
+ double control = 0.1;
+ //0.2 is a scaling factor that Jake used to define the magnitude of the
+ //vector of the current control point to be placed. I was basically
+ //taking advantage of the auto-drawing of Bezier curves that exists in
+ //the SVG format, and this is my attempt to give the control point the
+ //proper length.
+
+ // Experiment suggests that 0.2 gives distorsions with exp curves.
+ // 0.05 is just visually OK with 50 points, but 100 are better.
 
       for(; iter != series.series.end(); ++iter)
       {
- n_minus_2 = n_minus_1;
+ n_minus_2 = n_minus_1;
         n_minus_1 = n;
         n = *iter;
         transform_pair(n);
 
- back_vtr.first = ((n_minus_1.first - n.first) +
- (n_minus_2.first - n_minus_1.first)) * 0.2; // TODO why + 0.2
-
- back_vtr.second = ((n_minus_1.second - n.second) +
- (n_minus_2.second - n_minus_1.second)) * 0.2;
+ back_vtr.first = ((n_minus_1.first - n.first) + // (x diff - x previous diff) * control
+ (n_minus_2.first - n_minus_1.first)) * control;
+ back_vtr.second = ((n_minus_1.second - n.second) + // y
+ (n_minus_2.second - n_minus_1.second)) * control;
 
         // 8.3.6 The cubic Bézier curve commands path.S(x, y).
- path.S(n_minus_1.first + back_vtr.first,
- n_minus_1.second + back_vtr.second,
- n_minus_1.first, n_minus_1.second);
- }
-
- back_vtr.first = 0.;
- back_vtr.second = (n.second - n_minus_1.second)* 0.2;
- path.S(n.first + back_vtr.first,
- n.second + back_vtr.second,
- n.first, n.second);
+ // Start point, end point, & two control points.
+ // Example: S378.5,519.3 381,519.3 ...
+ // S end_control_point, end point
+ // Start is reflection of last point's control point.
+ path.S(n_minus_1.first + back_vtr.first, // x
+ n_minus_1.second + back_vtr.second, // y - end control point
+ n_minus_1.first, n_minus_1.second); // x, y - end point.
+ } // for
+ // Last point.
+ back_vtr.first = 0.;
+ back_vtr.second = (n.second - n_minus_1.second) * control;
+ path.S(n.first + back_vtr.first, // x
+ n.second + back_vtr.second, // y
+ n.first, n.second); // x, y
     }
     else
     { // Only one or two points, so no curving possible!
@@ -981,7 +1039,7 @@
     draw_title(); // Moved to ensure plot_X and Y are valid.
 
     // Define the clip path for the plot window.
- // We don't want to allow overlap of the plot window border lines,
+ // We don't want to allow overlap of the plot window border lines,
     // thus the minor adjustments.
     // TODO should this be border thickness?
 
@@ -1021,8 +1079,8 @@
       g_element& g_ptr = image.get_g_element(detail::PLOT_DATA_POINTS).add_g_element();
 
       g_ptr.style()
- .fill_color(series[i].point_style.fill_color)
- .stroke_color(series[i].point_style.stroke_color);
+ .fill_color(series[i].point_style.fill_color_)
+ .stroke_color(series[i].point_style.stroke_color_);
 
       for(std::multimap<double, double>::const_iterator j = series[i].series.begin();
         j != series[i].series.end(); ++j)
@@ -1048,7 +1106,7 @@
         x = j->first;
         y = j->second;
         transform_point(x, y);
- draw_plot_point(x, y, g_ptr, plot_point_style(blank, blank, series[i].point_style.size, cone));
+ draw_plot_point(x, y, g_ptr, plot_point_style(blank, blank, series[i].point_style.size_, cone));
         // TODO why are fill and stroke blank? How is point style for 'bad' values determined?
       }
     } // limits point
@@ -1077,7 +1135,7 @@
 
   svg_2d_plot& write(std::ostream& s_out)
   { // Write the image to an ostream.
- update_image();
+ update_image();
     image.write(s_out); // Use the ostream version of write.
     return *this;
   }
@@ -1165,21 +1223,14 @@
     return y_value_ioflags_;
   }
 
- //Derived& title(const std::string title)
- //{ // Plot title.
- // derived().title_info.text(title);
- // return derived();
- //}
-
   svg_2d_plot& y_axis_color(const svg_color& col)
- { // Set BOTH stroke and fill to the same color.
- image.get_g_element(detail::PLOT_Y_AXIS).style().fill_color(col);
+ { // Set only stroke color.
     image.get_g_element(detail::PLOT_Y_AXIS).style().stroke_color(col);
     return *this;
   }
 
   svg_color y_axis_color()
- { // But only return the stroke color.
+ { // eturn the stroke color.
     return image.get_g_element(detail::PLOT_Y_AXIS).style().stroke_color();
   }
 
@@ -1196,7 +1247,7 @@
   }
 
   svg_2d_plot& y_label_units_on(bool b)
- {
+ {
     use_y_label_units = b;
     return *this;
   }
@@ -1340,7 +1391,7 @@
     y_num_minor_ticks_ = num;
     return *this;
   }
-
+
   unsigned int y_num_minor_ticks()
   {
     return y_num_minor_ticks_;
@@ -1486,6 +1537,17 @@
     return y_label_info.font_size();
   }
 
+ svg_2d_plot& y_label_weight(std::string s)
+ { // "bold2 is only one that works so far.
+ y_label_info.font_weight(s);
+ return *this;
+ }
+
+ const std::string& y_label_weight()
+ {
+ return y_label_info.font_weight();
+ }
+
   svg_2d_plot& y_label_font_family(const std::string& family)
   {
     y_label_info.font_family(family);
@@ -1502,6 +1564,13 @@
   // TODO Probably better done this way,
   // but wait until parameter system removed.
 
+
+
+
+
+
+
+
   // plot member function, with several parameters, using Boost.Parameter,
   // to add data series to the plot window.
   // TODO replace this with chainable member functions.
@@ -1554,8 +1623,9 @@
   }
 }; // class svg_2d_plot : public detail::axis_plot_frame<svg_2d_plot>
 
-
- const std::string& svg_2d_plot::y_label_font_family()
+// sample of declared function, externally defined in another .cpp file.
+// TODO May be useful to refactor all functions this way.
+ const std::string& svg_2d_plot::y_label_font_family()
   {
     return y_label_info.font_family();
   }

Modified: sandbox/SOC/2007/visualization/boost/svg_plot/svg_style.hpp
==============================================================================
--- sandbox/SOC/2007/visualization/boost/svg_plot/svg_style.hpp (original)
+++ sandbox/SOC/2007/visualization/boost/svg_plot/svg_style.hpp 2007-12-11 10:53:51 EST (Tue, 11 Dec 2007)
@@ -26,6 +26,12 @@
 namespace svg
 {
 
+// Forward declarations of classes in svg_style.hpp
+class svg_style;
+class plot_point_style;
+class plot_line_style;
+class text_style;
+
 enum point_shape
 { // Marking a data point.
   // Used in draw_plot_point in axis_plot_frame.hpp
@@ -53,27 +59,80 @@
 // name circle changed to round to avoid clash with function named circle.
 };
 
-struct plot_point_style
+class plot_point_style
 {
- svg_color fill_color; // Color of the centre of the shape.
- svg_color stroke_color; // Color of circumference of shape.
- int size; // diameter of circle, height of square, font_size ...
- point_shape shape; // round, square, point...
- std::string symbols; // Unicode symbol (letters, digits, squiggles etc)
+public:
+ svg_color fill_color_; // Color of the centre of the shape.
+ svg_color stroke_color_; // Color of circumference of shape.
+ int size_; // diameter of circle, height of square, font_size ...
+ point_shape shape_; // round, square, point...
+ std::string symbols_; // Unicode symbol (letters, digits, squiggles etc)
     // Caution: not all Unicode symbols are output by all browsers!
     // const std::string font = "Lucida Sans Unicode";
     // TODO? devise way of setting this font?
+ //text_style style_;
 
- plot_point_style(const svg_color& fill, const svg_color& stroke,
+ plot_point_style(const svg_color& fill = blank, const svg_color& stroke = blank,
       int size = 10, point_shape shape = round, const std::string& symbols = "X")
         :
- fill_color(fill), stroke_color(stroke), size(size), shape(shape), symbols(symbols)
- { // TODO Should these be default colors?
+ fill_color_(fill), stroke_color_(stroke), size_(size), shape_(shape), symbols_(symbols)
+ { // TODO Should there be default colors? or "none" == blank?
     }
+
+ plot_point_style& size(int i)
+ {
+ size_ = i;
+ return *this;
+ }
+
+ int size()
+ {
+ return size_;
+ }
+
+ plot_point_style& fill_color(const svg_color& f)
+ {
+ fill_color_ = f;
+ return *this;
+ }
+
+ svg_color& fill_color()
+ {
+ return fill_color_;
+ }
+
+ plot_point_style& stroke_color(const svg_color& f)
+ {
+ stroke_color_ = f;
+ return *this;
+ }
+
+ svg_color& stroke_color()
+ {
+ return stroke_color_;
+ }
+
+ plot_point_style& shape(point_shape s)
+ {
+ shape_ = s;
+ return *this;
+ }
+
+ point_shape shape()
+ {
+ return shape_;
+ }
+
+ //text_style& style()
+ //{
+ // return style_;
+ //}
+
 }; // struct plot_point_style
 
-struct plot_line_style
+class plot_line_style
 { // TODO dotted and dashed line style? Useful for B&W?
+public:
     svg_color color; // line stroke color.
     svg_color area_fill; // Fill color from line to axis. == true means color.blank = true.
     bool line_on;
@@ -86,6 +145,105 @@
     }
 }; // struct plot_line_style
 
+
+class text_style
+{
+private:
+ int font_size_;
+ std::string font_family_;
+ std::string weight_;
+ std::string style_;
+ std::string stretch_;
+ std::string decoration_;
+
+public:
+ text_style(int size = 12,
+ const std::string& font = "Lucida Sans Unicode",
+ const std::string& style = "",
+ const std::string& weight = "",
+ const std::string& stretch = "",
+ const std::string& decoration = "")
+ : // Constructor.
+ font_size_(size),
+ font_family_(font),
+ style_(style),
+ weight_(weight),
+ stretch_(stretch),
+ decoration_(decoration)
+ { //text_style default constructor, defines defaults for all private members.
+ }
+
+ int font_size()
+ {
+ return font_size_;
+ }
+
+ text_style& font_size(unsigned int i)
+ { // pixels, default 10.
+ font_size_ = i;
+ return *this;
+ }
+
+ const std::string& font_family() const
+ {
+ return font_family_;
+ }
+
+ text_style& font_family(const std::string& s)
+ { // Examples: "Arial", "Times New Roman", "Verdana", "Lucida Sans Unicode"
+ font_family_ = s;
+ return *this;
+ }
+
+ const std::string& font_style() const
+ { // font-style: normal | bold | italic | oblique
+ return style_; // example "normal"
+ }
+
+ text_style& font_style(const std::string& s)
+ { // Examples: "italic"
+ style_ = s;
+ return *this;
+ }
+
+ const std::string& font_weight() const
+ {
+ return weight_;
+ }
+
+ text_style& font_weight(const std::string& s)
+ { // svg font-weight: normal | bold | bolder | lighter | 100 | 200 .. 900
+ // Examples: "bold", "normal"
+ weight_ = s;
+ return *this;
+ }
+
+ const std::string& font_stretch() const
+ {
+ return stretch_;
+ }
+
+ text_style& font_stretch(const std::string& s)
+ { // Examples: "wider" but implementation?
+ // font-stretch: normal | wider | narrower ...
+ stretch_ = s;
+ return *this;
+ }
+
+ const std::string& font_decoration() const
+ {
+ return decoration_;
+ }
+
+ text_style& font_decoration(const std::string& s)
+ { // Examples: "underline" | "overline" | "line-through"
+ decoration_ = s; // But implementation doubtful.
+ return *this;
+ }
+
+
+}; // class text_style
+
 // -----------------------------------------------------------------
 // This is the style information for any <g> tag.
 // This may be expanded to include more data from the SVG standard.
@@ -105,7 +263,7 @@
 public:
     svg_style() :
       fill_(svg_color(0, 0, 0)), // == black
- stroke_(svg_color(0, 0, 0)),
+ stroke_(svg_color(0, 0, 0)), // == black
       width_(0),
       fill_on_(false), stroke_on_(false), width_on_(false)
     { // Default constructor initialises all private data.
@@ -169,7 +327,7 @@
     {
         fill_ = col;
         fill_on_ = ! col.blank; // if blank fill is off or "none"
- return *this;
+ return *this; // Chainable.
     }
 
     svg_style& stroke_color(const svg_color& col)
@@ -188,26 +346,26 @@
     
     void write(std::ostream& rhs)
     { // Write any stroke, fill colors and/or width info (start with space).
- if(stroke_on_)
- {
- rhs << " stroke=\"";
- stroke_.write(rhs);
- rhs << "\"";
- }
- if(fill_on_)
- {
- rhs << " fill=\"";
- fill_.write(rhs);
- rhs << "\"";
- }
- if(width_on_)
- {
- rhs << " stroke-width=\""
- << width_
- << "\"";
- }
- } // void write
- // Examples: <g id="yMinorTicks" stroke="rgb(0,0,0)" stroke-width="1">
+ if(stroke_on_)
+ {
+ rhs << " stroke=\"";
+ stroke_.write(rhs);
+ rhs << "\"";
+ }
+ if(fill_on_)
+ {
+ rhs << " fill=\"";
+ fill_.write(rhs);
+ rhs << "\"";
+ }
+ if(width_on_)
+ { // TODO DO we ever want a 0 (or <0) width output???
+ rhs << " stroke-width=\""
+ << width_
+ << "\"";
+ }
+ // Examples: <g id="yMinorTicks" stroke="rgb(0,0,0)" stroke-width="1">
+ } // void write
 }; // class svg_style
 
 }//svg


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk