|
Boost-Commit : |
From: pbristow_at_[hidden]
Date: 2007-12-20 07:14:06
Author: pbristow
Date: 2007-12-20 07:14:05 EST (Thu, 20 Dec 2007)
New Revision: 42201
URL: http://svn.boost.org/trac/boost/changeset/42201
Log:
Some improvements to layout of legend box.
Text files modified:
sandbox/SOC/2007/visualization/boost/svg_plot/detail/axis_plot_frame.hpp | 4100 ++++++++++++++++++++-------------------
sandbox/SOC/2007/visualization/boost/svg_plot/svg_1d_plot.hpp | 10
sandbox/SOC/2007/visualization/boost/svg_plot/svg_2d_plot.hpp | 3203 +++++++++++++++---------------
3 files changed, 3669 insertions(+), 3644 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-20 07:14:05 EST (Thu, 20 Dec 2007)
@@ -23,2231 +23,2249 @@
namespace boost
{
-namespace svg
-{
-namespace detail
-{
-
- template <class Derived>
- class axis_plot_frame
+ namespace svg
{
- // axis_plot_frame is used as base class, for example:
- // class svg_1d_plot : public detail::axis_plot_frame<svg_1d_plot>
- // class svg_2d_plot : public detail::axis_plot_frame<svg_2d_plot>
- //protected:
- public:
- // --------------------------------------------------------------------
- // We don't use the SVG coordinate transform because then text would
- // be flipped. I'm considering using it to scale the image for resizes.
- // --------------------------------------------------------------------
-
- // protected member functions (defined below):
-
- // void transform_point(double &x, double &y);
- // void transform_x(double &x);
- // void transform_y(double &y);
- // void draw_x_minor_ticks(double j, path_element& tick_path, path_element& grid_path); // (& grid).
- // void draw_x_major_ticks(double i, path_element& tick_path, path_element& grid_path); // (& grid).
- // void draw_x_axis();
- // void draw_legend();
- // void draw_title();
- // void adjust_limits(double& x, double& y);
- // void draw_plot_point(double x, double y, g_element& g_ptr, const plot_point_style& sty);
-
- // Clear functions.
- // void clear_all(); // Calls all the other clear_* functions.
- // void clear_legend();
- // void clear_background();
- // void clear_x_axis();
- // void clear_y_axis();
- // void clear_title();
- // void clear_points();
- // 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;
- y = derived().y_scale * y + derived().y_shift;
- adjust_limits(x, y); // In case either hits max, min, infinity or NaN.
- }
- // TODO do we need to adjust_limit(x); // In case hits max, min, infinity or NaN?
- // This implies that user's choice of X-axis range is wrong?
- // So more drastic action like throwing might be least worst action?
-
- void transform_x(double & x)
- { // Scale and shift x only.
- x = derived().x_scale * x + derived().x_shift;
- }
-
- void transform_y(double & y)
- { // Scale and shift y only.
- y = derived().y_scale * y + derived().y_shift;
- }
-
- 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.
- double x1(value);
- transform_x(x1);
- double y1(0.); // Start on the horizontal X-axis line.
- double y2(derived().image.y_size());
+ enum legend_places
+ { // Placing of legend box, if requested by legend_on(true).
+ inside = 0, // Default place for inside is top left of plot window,
+ // exact location controlled by legend_top_left().
+ outside_left = -1, // Outside
+ outside_right = +1, // Default for outside.
+ outside_top = +2,
+ outside_bottom = -2
+ };
+
+ namespace detail
+ {
- // Draw the minor grid, if wanted.
- if(derived().use_x_minor_grid_)
+ template <class Derived>
+ class axis_plot_frame
{
- if(!derived().use_plot_window_)
- { // Use whole image.
- // Make space for title and X-axis labels.
- if(derived().use_title)
- { // Allow text_margin_ * font_size around text (pixels).
- y1 += derived().title_info.font_size() * derived().text_margin_;
+ // axis_plot_frame is used as base class, for example:
+ // class svg_1d_plot : public detail::axis_plot_frame<svg_1d_plot>
+ // class svg_2d_plot : public detail::axis_plot_frame<svg_2d_plot>
+ //protected:
+ public:
+ // --------------------------------------------------------------------
+ // We don't use the SVG coordinate transform because then text would
+ // be flipped. I'm considering using it to scale the image for resizes.
+ // --------------------------------------------------------------------
+
+ // protected member functions (defined below):
+
+ // void transform_point(double &x, double &y);
+ // void transform_x(double &x);
+ // void transform_y(double &y);
+ // void draw_x_minor_ticks(double j, path_element& tick_path, path_element& grid_path); // (& grid).
+ // void draw_x_major_ticks(double i, path_element& tick_path, path_element& grid_path); // (& grid).
+ // void draw_x_axis();
+ // void draw_legend();
+ // void draw_title();
+ // void adjust_limits(double& x, double& y);
+ // void draw_plot_point(double x, double y, g_element& g_ptr, const plot_point_style& sty);
+
+ // Clear functions.
+ // void clear_all(); // Calls all the other clear_* functions.
+ // void clear_legend();
+ // void clear_background();
+ // void clear_x_axis();
+ // void clear_y_axis();
+ // void clear_title();
+ // void clear_points();
+ // 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;
}
- if(derived().use_x_label)
+ j = s.find("e-000");
+ if (j != string::npos)
{
- y2 -= derived().x_label_info.font_size() * derived().text_margin_;
+ 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;
}
- }
- else
- { // use_plot_window_ == true.
- y1 = derived().plot_y1 + 1; // Top. Why +1 and -1?
- y2 = derived().plot_y2 - 1; // Bottom. Ensure *inside* window?
- }
- // Make sure that we are drawing inside the allowed window.
- if((x1 >= derived().plot_x1) && (x1 <= derived().plot_x2)) // allow = too?
- {
- //std::cerr << "Writing draw_x_minor_ticks grid inside plot window: x1 = "
- // << x1 << ", plot_x1 = " << derived().plot_x1 << ", plot_x2 = " << derived().plot_x2 << std::endl;
- grid_path.M(x1, y1).L(x1, y2);
- }
- else
- { // This will happen but is designed to be ignored!
- // TODO check this is best. See comment in draw_x_axis
- std::cerr << "Writing draw_x_minor_ticks grid OUTside plot window: x1 = "
- << x1 << ", plot_x1 = " << derived().plot_x1 << ", plot_x2 = " << derived().plot_x2 << std::endl;
- }
- } // use_x_minor_grid
- double x_tick_length = derived().x_minor_tick_length_;
- if(derived().use_x_ticks_on_plot_window_)
- { // Put minor ticks on the plot window border.
- y1 = derived().plot_y2; // on the window line.
- y2 = derived().plot_y2; // y1 = upper, y2 = lower end of tick.
- if(derived().use_up_ticks)
- { //
- y1 -= x_tick_length; // up.
- }
- if (derived().use_down_ticks)
- {
- y2 += x_tick_length; // down.
- }
- }
- else
- { // 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)
- {
- y1 -= x_tick_length; // up
- }
- if (derived().use_down_ticks)
- {
- y2 += x_tick_length; // down.
- }
- }
- // Make sure that we are drawing inside the allowed window.
- if((x1 >= derived().plot_x1) && (x1 <= derived().plot_x2)) // TODO allow < or <=
- {
- //std::cerr << "Writing draw_x_minor_ticks inside plot window: x1 = "
- // << x1 << ", plot_x1 = " << derived().plot_x1 << ", plot_x2 = " << derived().plot_x2 << std::endl;
- tick_path.M(x1, y1).L(x1, y2);
- // No value labels on minor ticks, at present.
- }
- else
- { // This will happen but is designed to be ignored!
- // TODO check this is best. See comment in draw_x_axis
- //std::cerr << "Writing draw_x_minor_ticks OUTside plot window: x1 = "
- // << x1 << ", plot_x1 = " << derived().plot_x1 << ", plot_x2 = " << derived().plot_x2 << std::endl;
- }
- } // void draw_x_minor_ticks
-
- void draw_x_major_ticks(double value, path_element& tick_path, path_element& grid_path)
- { // draw ticks - and grid too if wanted.
- // If use_x_major_labels then value may be shown beside the major tick.
- double x1(value); //
- transform_x(x1);
- double y1(0.); // // y1 = upper,
- double y2(derived().image.x_size()); // y2 = lower end of tick.
- if(derived().use_x_major_grid_)
- { // Draw major grid vertical line.
- if(!derived().use_plot_window_)
- { // Allow a modest margin around text of title and X-axis labels, if in use.
- if(derived().use_title)
- {
- y1 += derived().title_info.font_size() * derived().text_margin_;
- }
- if(derived().use_x_label)
- { // If use_x_major_labels then value may be shown beside the major tick.
- y2 -= derived().x_label_info.font_size() * derived().text_margin_;
- }
- }
- else
- { // use_plot_window_ == true
- y1 = derived().plot_y1; // Bottom of plot window.
- y2 = derived().plot_y2; // Top of plot window.
- }
- grid_path.M(x1, y1).L(x1, y2); // Vertical grid line.
- } // use_x_major_grid
-
- // Draw major tick (perhaps as well as grid - ticks might be wider than grid).
- // Make sure that we are drawing inside the allowed plot window.
- if((x1 >= derived().plot_x1) && (x1 <= derived().plot_x2)) // now <=
- {
- double x_tick_length = derived().x_major_tick_length_;
- if(derived().use_x_ticks_on_plot_window_)
- { // Put the ticks on the plot window border (was external).
- y1 = derived().plot_y2; // on the window line.
- y2 = derived().plot_y2; // y1 = upper, y2 = lower.
- if(derived().use_up_ticks)
- {
- y1 -= x_tick_length; // up
- }
- if (derived().use_down_ticks)
- {
- y2 += x_tick_length; // down.
- }
- }
- else
- { // Internal_style, draw tick from the central X axis line.
- y1 = derived().x_axis; // X-axis line.
- y2 = derived().x_axis;
- if(derived().use_up_ticks)
+ 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;
+ y = derived().y_scale * y + derived().y_shift;
+ adjust_limits(x, y); // In case either hits max, min, infinity or NaN.
+ }
+ // TODO do we need to adjust_limit(x); // In case hits max, min, infinity or NaN?
+ // This implies that user's choice of X-axis range is wrong?
+ // So more drastic action like throwing might be least worst action?
+
+ void transform_x(double & x)
+ { // Scale and shift x only.
+ x = derived().x_scale * x + derived().x_shift;
+ }
+
+ void transform_y(double & y)
+ { // Scale and shift y only.
+ y = derived().y_scale * y + derived().y_shift;
+ }
+
+ 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.
+ double x1(value);
+ transform_x(x1);
+ double y1(0.); // Start on the horizontal X-axis line.
+ double y2(derived().image.y_size());
+
+ // Draw the minor grid, if wanted.
+ if(derived().use_x_minor_grid_)
+ {
+ if(!derived().use_plot_window_)
+ { // Use whole image.
+ // Make space for title and X-axis labels.
+ if(derived().use_title)
+ { // Allow text_margin_ * font_size around text (pixels).
+ y1 += derived().title_info.font_size() * derived().text_margin_;
+ }
+ if(derived().use_x_label)
+ {
+ y2 -= derived().x_label_info.font_size() * derived().text_margin_;
+ }
+ }
+ else
+ { // use_plot_window_ == true.
+ y1 = derived().plot_y1 + 1; // Top. Why +1 and -1?
+ y2 = derived().plot_y2 - 1; // Bottom. Ensure *inside* window?
+ }
+ // Make sure that we are drawing inside the allowed window.
+ if((x1 >= derived().plot_x1) && (x1 <= derived().plot_x2)) // allow = too?
+ {
+ //std::cerr << "Writing draw_x_minor_ticks grid inside plot window: x1 = "
+ // << x1 << ", plot_x1 = " << derived().plot_x1 << ", plot_x2 = " << derived().plot_x2 << std::endl;
+ grid_path.M(x1, y1).L(x1, y2);
+ }
+ else
+ { // This will happen but is designed to be ignored!
+ // TODO check this is best. See comment in draw_x_axis
+ //std::cerr << "Writing draw_x_minor_ticks grid OUTside plot window: x1 = "
+ // << x1 << ", plot_x1 = " << derived().plot_x1 << ", plot_x2 = " << derived().plot_x2 << std::endl;
+ }
+ } // use_x_minor_grid
+
+ double x_tick_length = derived().x_minor_tick_length_;
+ if(derived().use_x_ticks_on_plot_window_)
+ { // Put minor ticks on the plot window border.
+ y1 = derived().plot_y2; // on the window line.
+ y2 = derived().plot_y2; // y1 = upper, y2 = lower end of tick.
+ if(derived().use_up_ticks)
+ { //
+ y1 -= x_tick_length; // up.
+ }
+ if (derived().use_down_ticks)
+ {
+ y2 += x_tick_length; // down.
+ }
+ }
+ else
+ { // 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)
+ {
+ y1 -= x_tick_length; // up
+ }
+ if (derived().use_down_ticks)
+ {
+ y2 += x_tick_length; // down.
+ }
+ }
+ // Make sure that we are drawing inside the allowed window.
+ if((x1 >= derived().plot_x1) && (x1 <= derived().plot_x2)) // TODO allow < or <=
+ {
+ //std::cerr << "Writing draw_x_minor_ticks inside plot window: x1 = "
+ // << x1 << ", plot_x1 = " << derived().plot_x1 << ", plot_x2 = " << derived().plot_x2 << std::endl;
+ tick_path.M(x1, y1).L(x1, y2);
+ // No value labels on minor ticks, at present.
+ }
+ else
+ { // This will happen but is designed to be ignored!
+ // TODO check this is best. See comment in draw_x_axis
+ //std::cerr << "Writing draw_x_minor_ticks OUTside plot window: x1 = "
+ // << x1 << ", plot_x1 = " << derived().plot_x1 << ", plot_x2 = " << derived().plot_x2 << std::endl;
+ }
+ } // void draw_x_minor_ticks
+
+ void draw_x_major_ticks(double value, path_element& tick_path, path_element& grid_path)
+ { // draw ticks - and grid too if wanted.
+ // If use_x_major_labels then value may be shown beside the major tick.
+ double x1(value); //
+ transform_x(x1);
+ double y1(0.); // // y1 = upper,
+ double y2(derived().image.x_size()); // y2 = lower end of tick.
+ if(derived().use_x_major_grid_)
+ { // Draw major grid vertical line.
+ if(!derived().use_plot_window_)
+ { // Allow a modest margin around text of title and X-axis labels, if in use.
+ if(derived().use_title)
+ {
+ y1 += derived().title_info.font_size() * derived().text_margin_;
+ }
+ if(derived().use_x_label)
+ { // If use_x_major_labels then value may be shown beside the major tick.
+ y2 -= derived().x_label_info.font_size() * derived().text_margin_;
+ }
+ }
+ else
+ { // use_plot_window_ == true
+ y1 = derived().plot_y1; // Bottom of plot window.
+ y2 = derived().plot_y2; // Top of plot window.
+ }
+ grid_path.M(x1, y1).L(x1, y2); // Vertical grid line.
+ } // use_x_major_grid
+
+ // Draw major tick (perhaps as well as grid - ticks might be wider than grid).
+ // Make sure that we are drawing inside the allowed plot window.
+ if((x1 >= derived().plot_x1) && (x1 <= derived().plot_x2)) // now <=
+ {
+ double x_tick_length = derived().x_major_tick_length_;
+ if(derived().use_x_ticks_on_plot_window_)
+ { // Put the ticks on the plot window border (was external).
+ y1 = derived().plot_y2; // on the window line.
+ y2 = derived().plot_y2; // y1 = upper, y2 = lower.
+ if(derived().use_up_ticks)
+ {
+ y1 -= x_tick_length; // up
+ }
+ if (derived().use_down_ticks)
+ {
+ y2 += x_tick_length; // down.
+ }
+ }
+ else
+ { // Internal_style, draw tick from the central X axis line.
+ y1 = derived().x_axis; // X-axis line.
+ y2 = derived().x_axis;
+ if(derived().use_up_ticks)
+ {
+ y1 -= x_tick_length; // up
+ }
+ if (derived().use_down_ticks)
+ {
+ y2 += x_tick_length; // down.
+ }
+ }
+ tick_path.M(x1, y1).L(x1, y2);
+ // Leaving current position at the bottom end of the tick.
+
+ if(derived().use_x_major_labels)
+ { // Show value by the tick as "1.2" or "3.4e+000"...
+ std::stringstream label;
+ 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)
+ { // No need to shift if derived().use_up_ticks as labels are below the X-axis.
+ // y += derived().x_label_value.font_size();
+ }
+ if (derived().x_label_rotation_ == upward)
+ { //
+ alignment = right_align;
+ //y += label.str().size() * derived().x_label_info.font_size();
+ // so the last digit will be by the tick.
+ }
+ else if((derived().x_label_rotation_ == downward)
+ || (derived().x_label_rotation_ == downhill))
+ { // start from tick and write down.
+ y += derived().x_label_value.font_size() * 0.5;
+ alignment = left_align;
+ }
+ else if(derived().x_label_rotation_ == horizontal)
+ {
+ y += derived().x_label_value.font_size() * 1.5;
+ alignment = center_align; // center on the tick.
+ }
+ else if(derived().x_label_rotation_ == uphill)
+ { // 45 slope up,
+ alignment = left_align; // Uphill to end at tick.
+ y += label.str().size() * derived().x_label_info.font_size() * 0.7;
+ // sloping up so need about sin(45) = 0.707 less space,
+ // so the last digit is by the tick.
+ }
+ else
+ { // 45 slope down.
+ alignment = left_align; // Assume downhill from tick,
+ // so no need for y adjustment.
+ }
+
+ { // ! use_x_ticks_on_plot_window_ = Internal - value labels just below horizontal X-axis.
+ if (derived().use_x_ticks_on_plot_window_ || ((value != 0) && derived().use_x_axis_lines_))
+ { // 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(),
+ "", "", "", "", alignment, // center label on the tick.
+ derived().x_label_rotation_);
+ }
+ }
+ } // use_x_major_labels
+ }
+ else
+ { // Outside plot window - so do nothing? Warning?
+ //std::cerr << "Writing draw_x_major_ticks OUTside plot window: "
+ // "x1 = " << x1 << ", plot_x1 = " << derived().plot_x1 << ", plot_x2 = " << derived().plot_x2 << std::endl;
+ }
+ } // draw_x_major_ticks
+
+ void draw_x_axis()
{
- y1 -= x_tick_length; // up
- }
- if (derived().use_down_ticks)
+ if(derived().use_x_axis_lines_)
+ { // Draw the horizontal X-axis line the full width of the plot window,
+ // perhaps including an addition in lieu of a major tick.
+ double xleft = derived().plot_x1;
+ double xright = derived().plot_x2;
+ if (derived().use_left_ticks && derived().use_x_ticks_on_plot_window_
+ && (derived().y_axis_position_ == y_intersect))
+ { // Extend the horizontal line left in lieu of longest tick.
+ xleft -= (std::max)(derived().y_minor_tick_length_, derived().y_major_tick_length_);
+ }
+ double y = derived().x_axis; // y = 0, (provided y range includes zero).
+ derived().image.get_g_element(PLOT_X_AXIS).line(
+ xleft, y,
+ xright, y);
+ }
+
+ // Access the paths for the ticks & grids, ready for additions.
+ path_element& minor_tick_path = derived().image.get_g_element(PLOT_X_MINOR_TICKS).path();
+ path_element& major_tick_path = derived().image.get_g_element(PLOT_X_MAJOR_TICKS).path();
+ path_element& minor_grid_path = derived().image.get_g_element(PLOT_X_MINOR_GRID).path();
+ path_element& major_grid_path = derived().image.get_g_element(PLOT_X_MAJOR_GRID).path();
+
+ // x_minor_jump is the interval between minor ticks.
+ double x_minor_jump = derived().x_major_interval_ /
+ (derived().x_num_minor_ticks_ + 1.);
+
+ // 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_) * (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, 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 the ticks on the negative side (left of zero).
+ for(double x = 0.; x >= derived().x_min; x -= derived().x_major_interval_)
+ {
+ // Draw minor ticks.
+ 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)
+ {
+ 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);
+ }
+ }
+ } // void draw_x_axis()
+
+ // --------------------------------------------------------------------
+ // Draw functions - legend & title (if any).
+ // --------------------------------------------------------------------
+
+ void draw_title()
{
- y2 += x_tick_length; // down.
- }
- }
- tick_path.M(x1, y1).L(x1, y2);
- // Leaving current position at the bottom end of the tick.
-
- if(derived().use_x_major_labels)
- { // Show value by the tick as "1.2" or "3.4e+000"...
- std::stringstream label;
- 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)
- { // No need to shift if derived().use_up_ticks as labels are below the X-axis.
- // y += derived().x_label_value.font_size();
- }
- if (derived().x_label_rotation_ == upward)
- { //
- alignment = right_align;
- //y += label.str().size() * derived().x_label_info.font_size();
- // so the last digit will be by the tick.
- }
- else if((derived().x_label_rotation_ == downward)
- || (derived().x_label_rotation_ == downhill))
- { // start from tick and write down.
- y += derived().x_label_value.font_size() * 0.5;
- alignment = left_align;
- }
- else if(derived().x_label_rotation_ == horizontal)
+ // Update title_info with position.
+ derived().title_info.x(derived().image.x_size() / 2.); // Center of image.
+ // Assumes align = center_align.
+ double y;
+ if (derived().use_plot_window_)
+ {
+ y = derived().plot_y1; // plot_y1 IS now assigned in calculate_plot_window
+ // y is distance from top of image to top of plot window.
+ y /= derived().text_margin_; // Center the title in the space between.
+ }
+ else
+ { // 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 size_legend_box()
+ { // Calculate how big the legend box needs to be.
+ // Store in legend_width_ and legend_height_
+ if(derived().use_legend == false)
+ { // No legend, so set values to show legend position invalid.
+ derived().legend_left_ = -1;
+ derived().legend_right_ = -1;
+ derived().legend_top_ = -1;
+ derived().legend_bottom_ = -1;
+ derived().legend_height_ = 0;
+ derived().legend_width_ = 0;
+ return;
+ }
+ else
+ { // use_legend == true
+ // 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 height of whichever is the biggest of point marker and font.
+ double spacing = (std::max)(font_size, point_size);
+ // std::cout << spacing << ' ' << font_size << ' ' << point_size << std::endl;
+ bool is_header = (derived().legend_header_.text() != "");
+
+ 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();
+ if (siz > longest)
+ {
+ longest = siz;
+ }
+ } // for
+ std::cout.flags(std::ios_base::dec);
+ std::cout << "\nLongest legend header or data descriptor " << longest << " chars" << 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.
+ derived().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.
+ derived().legend_width_ += spacing * 2.;
+ }
+ if(derived().series[0].point_style.shape() != none)
+ { // colored data point marker, cross, round... & space
+ derived().legend_width_ += 2 * derived().series[0].point_style.size();
+ }
+ // else no point marker.
+
+ // legend_height must be *at least* enough for
+ // 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.
+ derived().legend_height_ = spacing; // At top
+ if (is_header) // is a legend header line.
+ {
+ derived().legend_height_ += 2 * font_size; // text & space after.
+ }
+ derived().legend_height_ += num_series * spacing * 2; // Space for the data point symbols & text.
+ } // use_legend == true
+
+ std::cout << "Legend width " << derived().legend_width_
+ << ", height " << derived().legend_height_ << std::endl;
+ } // void size_legend_box()
+
+ void place_legend_box()
{
- y += derived().x_label_value.font_size() * 1.5;
- alignment = center_align; // center on the tick.
- }
- else if(derived().x_label_rotation_ == uphill)
- { // 45 slope up,
- alignment = left_align; // Uphill to end at tick.
- y += label.str().size() * derived().x_label_info.font_size() * 0.7;
- // sloping up so need about sin(45) = 0.707 less space,
- // so the last digit is by the tick.
- }
- else
- { // 45 slope down.
- alignment = left_align; // Assume downhill from tick,
- // so no need for y adjustment.
- }
+ if(derived().use_legend) // Legend box required.
+ {
+ derived().use_outside_legend_ = true; // Unless proves to be inside.
+ switch (derived().legend_place_)
+ {
+ case inside:
+ derived().use_outside_legend_ = false;
+ if (derived().legend_left_ == -1)
+ { // Legend box position NOT been set by legend_top_left.
+ // Default inside position is top left of plot window.
+ derived().legend_left_ = derived().plot_x1;
+ derived().legend_right_ = derived().plot_x1 + derived().legend_width_;
+ derived().plot_x1 = derived().legend_right_;
+ derived().legend_top_ = derived().plot_y1; // Level with top of plot window.
+ if (derived().use_title)
+ {
+ derived().legend_top_ += derived().title_font_size() * 2.; // below title.
+ }
+ derived().legend_bottom_ = derived().legend_top_ + derived().legend_height_;
+ }
+ else
+ { // Legend position has been specified by legend_top_left.
+ break;
+ }
+ break;
+ // If outside then reserve space for legend by reducing plot window.
+ case outside_right:
+ derived().legend_right_ = derived().plot_x2; // right image edge less border.
+ derived().legend_right_ -= derived().y_label_font_size() * 2.; // space from right edge.
+ derived().legend_left_ = derived().legend_right_ - derived().legend_width_;
+ derived().plot_x2 = derived().legend_left_; // Narrow plot window from left.
+ derived().plot_x2 -= derived().y_label_font_size() * 2.; // space.
+ derived().legend_top_ = derived().plot_y1; // Level with top of plot window.
+ derived().legend_top_ += derived().y_label_font_size() * 2.; // TODO ???
+ derived().legend_bottom_ = derived().legend_top_ + derived().legend_height_;
+ break;
+ case outside_left:
+ // TODO implement.
+ break;
+ case outside_top:
+ break;
+ case outside_bottom:
+ break;
+ } // switch
+
+ std::cout << "Legend: left " << derived().legend_left_
+ << ", right " << derived().legend_right_
+ << ", top " << derived().legend_top_
+ << ", bottom " << derived().legend_bottom_
+ << std::endl;
+
+ // Check if the location requested will fit,
+ // now that we know the size of box needed.
+ if ( (derived().legend_left_ < 0) || (derived().legend_left_ > derived().image.x_size()))
+ { // left outside image?
+ std::cout << "Legend top left " << derived().legend_left_
+ << " is outside image size = " << derived().image.x_size() << std::endl;
+ }
+ if ((derived().legend_right_ < 0) || (derived().legend_right_ > derived().image.x_size()))
+ { // right outside image?
+ std::cout << "Legend top right " << derived().legend_right_
+ << " is outside image size = " << derived().image.x_size() << std::endl;
+ }
+ if ((derived().legend_top_ < 0) || (derived().legend_top_ > derived().image.y_size()))
+ { // top outside image?
+ std::cout << "Legend top " << derived().legend_top_
+ << " outside image!" << derived().image.y_size() << std::endl;
+ }
+ if ((derived().legend_bottom_ < 0 ) || (derived().legend_bottom_ > derived().image.y_size()))
+ { // bottom outside image?
+ std::cout << "Legend bottom " << derived().legend_bottom_
+ << " outside " << derived().image.y_size() << std::endl;
+ }
+
+ // 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_left_, derived().legend_top_, derived().legend_width_, derived().legend_height_));
+ } // if use_legend
+ } // 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;
+ }
+ }
+ // Assume legend box position has already been sized by calculate_legend_box.
+ double legend_x_start = derived().legend_left_; // Saved box location.
+ double legend_width = derived().legend_width_;
+ double legend_y_start = derived().legend_top_;
+ 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));
+
+ double legend_y_pos = legend_y_start + derived().text_margin_ * spacing;
+ if (is_header)
+ { // 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_));
+ legend_y_pos += 2 * spacing;
+ }
+
+ g_ptr = &(derived().image.get_g_element(PLOT_LEGEND_POINTS));
+ g_element* g_inner_ptr = g_ptr;
+ g_inner_ptr = &(derived().image.get_g_element(PLOT_LEGEND_TEXT));
+
+ for(unsigned int i = 0; i < derived().series.size(); ++i)
+ { // Show point marker, text info and perhaps line for all the data series.
+ double legend_x_pos = legend_x_start;
+ g_inner_ptr = &(g_ptr->add_g_element());
+ // Use both stroke colors from the point's style.
+ g_inner_ptr->style()
+ .stroke_color(derived().series[i].point_style.stroke_color_);
+ g_inner_ptr->style().stroke_width(2); // TODO create a global for this
+
+ if(derived().series[i].point_style.shape() != none)
+ {
+ draw_plot_point( // Plot point like circle, square...
+ legend_x_start + spacing / 2, // space before point marker.
+ legend_y_pos,
+ *g_inner_ptr,
+ derived().series[i].point_style);
+ legend_x_pos += 1.0 * spacing;
+ }
+
+ // Line markers - only really applicable to 2-D sets plot_line_style,
+ if (derived().use_line)
+ { // Need to draw a short line to show color for that data series.
+ g_inner_ptr->style() // Use fill & stroke colors from line style.
+ .stroke_color(derived().series[i].line_style.color);
+ g_inner_ptr->push_back(new line_element(
+ legend_x_pos + spacing /2., // half space leading space
+ legend_y_pos,
+ legend_x_pos + spacing * 2., // line sample is two char long.
+ legend_y_pos));
+ legend_x_pos += 2.5 * spacing; // short line & half space.
+ } // use_line
+
+ // Legend text for each Data Series added to the plot.
+ g_inner_ptr = &(derived().image.get_g_element(PLOT_LEGEND_TEXT));
+ g_inner_ptr->push_back(new text_element(
+ legend_x_pos, // allow space for the marker.
+ legend_y_pos,
+ derived().series[i].title, // Text for this data series.
+ derived().legend_header_.font_size(), // font size &
+ derived().legend_header_.font_family(), // font family.
+ "", "", "", "",
+ left_align));
+ legend_y_pos += 2 * spacing;
+ } // for
+ } // void draw_legend()
+
+ void draw_x_label()
+ {
+ // color is set in constructor.
+ //image.get_g_element(detail::PLOT_X_LABEL).style().stroke_color(black);
+ // and using y_label_color(color)
+
+ std::string label = derived().x_label_info.text(); // x_axis label, and optional units.
+ if (derived().use_x_label_units && (derived().x_units_info.text() != ""))
+ { // Append the units, if any, providing brackets ().
+ label += " (" + derived().x_units_info.text() + ")";
+ }
+ // Simplest to start from the bottom of the image.
+ // and move up to give enough space for the X-axis label.
+
+ double y = derived().image.y_size(); // bottom edge of image.
+ y -= derived().x_label_font_size(); // Up enough for a space underneath label.
+ derived().image.get_g_element(PLOT_X_LABEL).push_back(new text_element(
+ ( // x position relative to the x-axis which is middle of plot window.
+ derived().plot_x2 + derived().plot_x1) / 2, // x coordinate - middle.
+ y, // Up from image bottom edge.
+ label,
+ derived().x_label_font_size(),
+ derived().x_label_font_family(), "", "", "", "", center_align, horizontal)
+ );
+ } // void draw_x_label()
+
+ // TODO split into adjust_limit(double& x) and call twice?,
+ // and TODO use to check 1-D for limit values too?
+ void adjust_limits(double& x, double& y)
+ { // If value reaches limit of max, min, infinity,
+ // use the appropriate plot min or max.
+ if(detail::limit_max(x))
+ {
+ x = derived().plot_x2;
+ }
+ if(detail::limit_max(y))
+ {
+ y = derived().plot_y1;
+ }
+ if(detail::limit_min(x))
+ {
+ x = derived().plot_x1;
+ }
+ if(detail::limit_min(y))
+ {
+ y = derived().plot_y1;
+ }
+ // If value is NaN, use zero instead.
+ // TODO Do we want/get a different color or shape for NaNs??
+ if(detail::limit_NaN(x))
+ {
+ x = 0;
+ transform_x(x);
+ }
+ if(detail::limit_NaN(y))
+ {
+ y = 0;
+ transform_y(y);
+ }
+ } // void adjust_limits
+
+ void draw_plot_point(double x, double y,
+ g_element& g_ptr,
+ const plot_point_style& sty)
+ {
+ int size = sty.size_;
+ double half_size = size / 2.;
- { // ! use_x_ticks_on_plot_window_ = Internal - value labels just below horizontal X-axis.
- if (derived().use_x_ticks_on_plot_window_ || ((value != 0) && derived().use_x_axis_lines_))
- { // 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(),
- "", "", "", "", alignment, // center label on the tick.
- derived().x_label_rotation_);
+ // For 1-D plots, the points do not *need* to be centered on the X-axis,
+ // and putting them just above, or sitting on, the X-axis is much clearer.
+ // For 2-D plots, the symbol center should, of course,
+ // be *centered exactly* on x, y.
+ // circle and ellipse are naturally centered on the point.
+ // for rect x and y half_size offset centers square on the point.
+ // But symbols are in a rectangular box and the offset is different for x & y
+ // even assuming that the symbol is centered in the rectangle.
+ // 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
+ {
+ case round:
+ g_ptr.circle(x, y, half_size);
+ break;
+ case square:
+ g_ptr.rect(x - half_size, y - half_size, size, size);
+ break;
+ case egg:
+ g_ptr.ellipse(x, y, half_size, size * 2.); // Tall thin egg!
+ break;
+
+ // Offset from center is not an issue with vertical or horizontal ticks.
+ // TODO stroke color of line seems to be FILL color, not the stroke color.
+ // This is OK-ish, but I'm not sure why.
+
+ //svg_color sc = sty.stroke_color;
+ //svg_color fc = sty.fill_color;
+
+ case vertical_tick: // Especially neat for 1-D points.
+ g_ptr.line(x, y, x , y - size); // tick up from axis.
+ break;
+ case vertical_line:
+ g_ptr.line(x, y + size, x , y - size); // line up & down from axis.
+ break;
+ case horizontal_tick:
+ // horizontal_tick is pretty useless for 1-D because the horizontal line is on the X-axis.
+ g_ptr.line(x, y, x + size, y ); // tick right from axis.
+ break;
+ case horizontal_line:
+ g_ptr.line(x, y - size, x + size, y ); // line left & right from axis.
+ // horizontal_line is pretty useless for 1-D because the horizontal line is on the X-axis.
+ break;
+
+ case symbol:
+ 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
+ // boost\math_toolkit\libs\math\doc\sf_and_dist\html4_symbols.qbk,
+ // http://www.htmlhelp.com/reference/html40/entities/symbols.html
+ // and http://www.alanwood.net/demos/ent4_frame.html
+ // The Unicode value in decimal 9830 or hex x2666 must be prefixed with & and terminated with ;
+ // for example &x2666; for xml
+ // and then enveloped with "" to convert to a std::string, for example: "♦" for diamond.
+
+ break;
+ case diamond:
+ g_ptr.text(x, y, "♦", size, "Lucida Sans Unicode");
+ // size / 4. puts bottom tip on the X-axis,
+ // size / 2. put center above the X-axis
+ // x, y, put on the X-axis - probably what is needed for 2-D plots.
+ // diamond, spades, clubs & hearts fill with expected fill_color.
+ break;
+ case asterisk:
+ g_ptr.text(x, y - size / 3., "∗", size, "Lucida Sans Unicode");
+ // asterisk is black filled.
+ // size /3 puts the bottom tip on the X-axis.
+ break;
+ case lozenge:
+ g_ptr.text(x, y - size / 3., "◊", size, "Lucida Sans Unicode");
+ // size / 3 to get tip of lozenge just on the X-axis.
+ // lozenge seems not to fill?
+ break;
+ case club:
+ g_ptr.text(x, y, "♣", size, "Lucida Sans Unicode");
+ // x, y, puts club just on the X-axis
+ break;
+ case spade:
+ g_ptr.text(x, y, "♠", size, "Lucida Sans Unicode");
+ //
+ break;
+ case heart:
+ g_ptr.text(x, y , "♥", size, "Lucida Sans Unicode");
+ //
+ break;
+ case cone: // Pointing down triangle.
+ g_ptr.triangle(x - half_size, y - size, x + half_size, y - size, x, y, false);
+ // Last point puts the bottom tip of the triangle on the X-axis.
+ // This may not be wanted for 2-D.
+ break;
+ case cross:
+ g_ptr.line(x, y + size, x , y - size); // line up & down from axis,
+ g_ptr.line(x, y - size, x + size, y ); // & line left & right from axis.
+ // Cross is pretty useless for 1-D because the horizontal line is on the X-axis.
+
+ break;
+ // TODO Other point_shapes do nothing yet.
+ }
+ } // void draw_plot_point
+
+ // -----------------------------------------------------------------
+ // Clear Functions.
+ // When writing to multiple documents, the contents of the plot
+ // may change significantly between. Rather than figuring out what
+ // has and has not changed, just erase the contents of the
+ // legend, title... in the document and start over.
+ // -----------------------------------------------------------------
+
+ void clear_all()
+ {
+ clear_legend();
+ clear_background();
+ clear_x_axis();
+ clear_y_axis();
+ clear_title();
+ clear_points();
+ clear_plot_background();
+ clear_grids();
}
- }
- } // use_x_major_labels
- }
- else
- { // Outside plot window - so do nothing? Warning?
- //std::cerr << "Writing draw_x_major_ticks OUTside plot window: "
- // "x1 = " << x1 << ", plot_x1 = " << derived().plot_x1 << ", plot_x2 = " << derived().plot_x2 << std::endl;
- }
- } // draw_x_major_ticks
- void draw_x_axis()
- {
- if(derived().use_x_axis_lines_)
- { // Draw the horizontal X-axis line the full width of the plot window,
- // perhaps including an addition in lieu of a major tick.
- double xleft = derived().plot_x1;
- double xright = derived().plot_x2;
- if (derived().use_left_ticks && derived().use_x_ticks_on_plot_window_
- && (derived().y_axis_position_ == y_intersect))
- { // Extend the horizontal line left in lieu of longest tick.
- xleft -= (std::max)(derived().y_minor_tick_length_, derived().y_major_tick_length_);
- }
- double y = derived().x_axis; // y = 0, (provided y range includes zero).
- derived().image.get_g_element(PLOT_X_AXIS).line(
- xleft, y,
- xright, y);
- }
-
- // Access the paths for the ticks & grids, ready for additions.
- path_element& minor_tick_path = derived().image.get_g_element(PLOT_X_MINOR_TICKS).path();
- path_element& major_tick_path = derived().image.get_g_element(PLOT_X_MAJOR_TICKS).path();
- path_element& minor_grid_path = derived().image.get_g_element(PLOT_X_MINOR_GRID).path();
- path_element& major_grid_path = derived().image.get_g_element(PLOT_X_MAJOR_GRID).path();
-
- // x_minor_jump is the interval between minor ticks.
- double x_minor_jump = derived().x_major_interval_ /
- (derived().x_num_minor_ticks_ + 1.);
+ void clear_background()
+ {
+ derived().image.get_g_element(PLOT_BACKGROUND).clear();
+ }
- // 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_) * (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, 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);
- }
- }
+ void clear_title()
+ {
+ derived().image.get_g_element(PLOT_TITLE).clear();
+ }
- // Draw the ticks on the negative side (left of zero).
- for(double x = 0.; x >= derived().x_min; x -= derived().x_major_interval_)
- {
- // Draw minor ticks.
- 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.
+ void clear_points()
+ {
+ derived().image.get_g_element(PLOT_DATA_POINTS).clear();
+ }
- j -= x_minor_jump)
- {
- 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);
- }
- }
- } // void draw_x_axis()
-
- // --------------------------------------------------------------------
- // Draw functions - legend & title (if any).
- // --------------------------------------------------------------------
+ void clear_plot_background()
+ {
+ derived().image.get_g_element(PLOT_WINDOW_BACKGROUND).clear();
+ }
- void draw_title()
- {
- // Update title_info with position.
- derived().title_info.x(derived().image.x_size() / 2.); // Center of image.
- // Assumes align = center_align.
- double y;
- if (derived().use_plot_window_)
- {
- y = derived().plot_y1; // plot_y1 IS now assigned in calculate_plot_window
- // y is distance from top of image to top of plot window.
- y /= derived().text_margin_; // Center the title in the space between.
- }
- else
- { // 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 clear_legend()
+ {
+ derived().image.get_g_element(PLOT_LEGEND_BACKGROUND).clear();
+ derived().image.get_g_element(PLOT_LEGEND_POINTS).clear();
+ derived().image.get_g_element(PLOT_LEGEND_TEXT).clear();
+ }
- void calculate_legend_box()
- {
- 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 height of whichever is the biggest of point marker and font.
-
- double spacing = (std::max)(font_size, point_size);
- std::cout << spacing << ' ' << font_size << ' ' << point_size << std::endl;
- bool is_header = (derived().legend_header_.text() != "");
-
- 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();
- if (siz > longest)
- {
- longest = siz;
- }
- }
- std::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 * 2.;
- }
- 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
- // 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; // At top
- if (is_header) // is a legend header.
- {
- 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.
- std::cout << "Legend X left " << derived().legend_x1_
- << " outside image!" << derived().image.x_size() << std::endl;
- }
- else if ((derived().legend_y1_ < 0) || (derived().legend_y1_ > derived().image.y_size()))
- {// Outside image.
- std::cout << "Legend Y top " << derived().legend_y1_
- << " outside image!" << derived().image.y_size() << std::endl;
- }
- if (derived().legend_x1_ + legend_height > derived().image.x_size())
- { // Too wide!
- std::cout << "Legend " << derived().legend_x1_
- << " too wide by " << legend_width - derived().image.x_size() << std::endl;
- }
- else if (derived().legend_y1_ + legend_height > derived().image.y_size())
- {
- std::cout << "Legend Y left " << derived().legend_y1_
- << " too high by " << legend_height - derived().image.y_size() << std::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?
- std::cout << "Legend X left " << legend_x_start
- << " outside image!" << derived().image.x_size() << std::endl;
- }
- else if ((legend_y_start < 0) || (legend_y_start > derived().image.y_size()))
- { // Outside image - should never happen but check anyway?
- std::cout << "Legend Y top " << legend_y_start
- << " outside image!" << derived().image.y_size() << std::endl;
- }
- if (derived().legend_header_.x() + legend_height > derived().image.x_size())
- { // Too wide!
- std::cout << "Legend " << derived().legend_header_.x()
- << " too wide by " << legend_width - derived().image_x_size() << std::endl;
- }
- else if (derived().legend_header_.y() + legend_height > derived().image.y_size())
- {
- std::cout << "Legend Y left " << derived().legend_header_.y()
- << " too high by " << legend_height - derived().image.y_size() << std::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;
- }
-
- // 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));
-
- std::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_ << std::endl;
+ void clear_x_axis()
+ {
+ derived().image.get_g_element(PLOT_X_AXIS).clear();
+ derived().image.get_g_element(PLOT_X_MINOR_TICKS).clear();
+ derived().image.get_g_element(PLOT_X_MAJOR_TICKS).clear();
+ derived().image.get_g_element(PLOT_X_LABEL).clear();
+ derived().image.get_g_element(PLOT_VALUE_LABELS).clear();
+ }
- } // void calculate_legend_box()
+ void clear_y_axis()
+ {
+ derived().image.get_g_element(PLOT_Y_AXIS).clear();
+ }
- 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;
- }
- }
- // 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));
-
- double legend_y_pos = legend_y_start + derived().text_margin_ * spacing;
- if (is_header)
- { // 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_));
- legend_y_pos += 2 * spacing;
- }
-
- g_ptr = &(derived().image.get_g_element(PLOT_LEGEND_POINTS));
- g_element* g_inner_ptr = g_ptr;
- g_inner_ptr = &(derived().image.get_g_element(PLOT_LEGEND_TEXT));
-
- for(unsigned int i = 0; i < derived().series.size(); ++i)
- { // Show point marker, text info and perhaps line for all the data series.
- double legend_x_pos = legend_x_start;
- g_inner_ptr = &(g_ptr->add_g_element());
- // Use both stroke colors from the point's style.
- g_inner_ptr->style()
- .stroke_color(derived().series[i].point_style.stroke_color_);
- g_inner_ptr->style().stroke_width(2); // TODO create a global for this
+ void clear_grids()
+ {
+ derived().image.get_g_element(PLOT_X_MAJOR_GRID).clear();
+ derived().image.get_g_element(PLOT_X_MINOR_GRID).clear();
+ // TODO don't we need to clear Y grids too??????
+ derived().image.get_g_element(PLOT_Y_MAJOR_GRID).clear();
+ derived().image.get_g_element(PLOT_Y_MINOR_GRID).clear();
+ }
- if(derived().series[i].point_style.shape() != none)
- {
- draw_plot_point( // Plot point like circle, square...
- legend_x_start + spacing / 2, // space before point marker.
- legend_y_pos,
- *g_inner_ptr,
- derived().series[i].point_style);
- legend_x_pos += 1.0 * spacing;
- }
-
- // Line markers - only really applicable to 2-D sets plot_line_style,
- if (derived().use_line)
- { // Need to draw a short line to show color for that data series.
- g_inner_ptr->style() // Use fill & stroke colors from line style.
- .stroke_color(derived().series[i].line_style.color);
- g_inner_ptr->push_back(new line_element(
- legend_x_pos + spacing /2., // half space leading space
- legend_y_pos,
- legend_x_pos + spacing * 2., // line sample is two char long.
- legend_y_pos));
- legend_x_pos += 2.5 * spacing; // short line & half space.
- } // use_line
-
- // Legend text for each Data Series added to the plot.
- g_inner_ptr = &(derived().image.get_g_element(PLOT_LEGEND_TEXT));
- g_inner_ptr->push_back(new text_element(
- legend_x_pos, // allow space for the marker.
- legend_y_pos,
- derived().series[i].title, // Text for this data series.
- derived().legend_header_.font_size(), // font size &
- derived().legend_header_.font_family(), // font family.
- "", "", "", "",
- left_align));
- legend_y_pos += 2 * spacing;
- } // for
-
- // TODO reconsider this.
- //if(derived().plot_x2 >= (int)derived().image.x_size())
- //{ // Put legend above plot because image is tall & thin.
- // // TODO this with use control of the legend box position.
- //}
- } // void draw_legend()
+ private:
+ Derived& derived()
+ {
+ return static_cast<Derived&>(*this); // Why is cast required?
+ // error C2440: 'return' : cannot convert from 'boost::svg::detail::axis_plot_frame<Derived>' to 'boost::svg::svg_1d_plot &'
+ }
+ const Derived& derived()const
+ {
+ return static_cast<const Derived&>(*this);
+ }
+ public:
+ // Set & get member function Declarations:
+ // See svg_fwd.hpp
+ // -----------------------------------------------------------------
+
+ // Get functions:
+ // =========== Image & plot window ==============
+ // Derived& image_size(unsigned int x, unsigned int y);
+ // unsigned int image_x_size();
+ // unsigned int image_y_size()
+ // bool plot_window_on()
+ // svg_color background_color()
+ // svg_color background_border_color()
+ // svg_color plot_background_color()
+ //
+ // std::pair<double, double> plot_window_x()
+ // std::pair<double, double> plot_window_y()
+
+ // ========= Title & legend ============
+ // bool title_on()
+ // const std::string title()
+ // unsigned int title_font_size()
+ // const std::string title_font()
+ // svg_color title_color()
+ // bool legend_on()
+ // const std::string legend_title()
+ // svg_color legend_background_color()
+ // svg_color legend_border_color()
+ // unsigned int legend_title_font_size()
+ // ========= Axes & Ticks ============
+ // bool x_axis_on()
+ // unsigned int x_axis_width()
+ // bool x_external_style_on()
+ // bool x_ticks_up_on()
+ // bool x_ticks_down_on()
+ // std::pair<double, double> x_range()
+ // double x_minimum()
+ // double x_maximum()
+ // double x_major_interval()
+ // unsigned int x_num_minor__ticks()
+ // double x_major_tick()
+ // svg_color x_major_tick_color()
+ // svg_color x_minor_tick_color()
+ // unsigned int x_major_tick_length()
+ // unsigned int x_major_tick_width_()
+ // unsigned int x_minor_tick_length_()
+ // unsigned int x_minor_tick_width_()
+ // ========= Labels ============
+ // bool x_label_on() // Show X-axis label text.
+ // std::string x_label()
+ // bool x_label_units_on() //
+ // std::string x_label_units() // Show X-axis units text.
+ // bool x_major_labels_on()
+ // svg_color x_label_color()
+ // bool axes_on()
+ // svg_color x_axis_color()
+ // bool y_axis_on()
+ // svg_color y_axis_color()
+ // std::string y_label()
+ // svg_color y_label_color()
+ // ========= grid ============
+ // bool x_major_grid_on()
+ // bool x_minor_grid_on()
+ // unsigned int x_major_grid_width()
+ // unsigned int x_minor_grid_width()
+ // svg_color x_major_grid_color()
+ // svg_color x_minor_grid_color()
+
+ // Set functions:
+
+ //Derived& image_size(unsigned int x, unsigned int y)
+ //Derived& image_x_size(unsigned int x);
+ //Derived& image_y_size(unsigned int y);
+
+ //Derived& title(const std::string& title)
+
+ //Derived& document_title(const std::string&);
+ //Derived& description(const std::string&);
+ //Derived& copyright_date(const std::string&);
+ //Derived& copyright_holder(const std::string&);
+
+ //Derived& title_font_size(unsigned int size)
+ //Derived& legend_title_font_size(unsigned int size)
+ //Derived& legend_on(bool cmd)
+ //Derived& plot_window_on(bool cmd)
+ //Derived& plot_window_x(unsigned int min_x, unsigned int max_x)
+ //Derived& plot_window_y(unsigned int min_y, unsigned int max_y)
+ //Derived& x_external_style_on(bool cmd)
+ //Derived& x_ticks_up_on(bool cmd)
+ //Derived& x_ticks_down_on(bool cmd)
+ //Derived& x_label_on(bool cmd)
+ //Derived& x_label_units_on(bool cmd)
+ //Derived& x_major_labels_on(bool cmd)
+ //Derived& title_on(bool cmd)
+ //Derived& x_major_grid_on(bool is)
+ //Derived& x_minor_grid_on(bool is)
+ //Derived& axes_on(bool is)
+ //Derived& x_axis_on(bool is)
+ //Derived& y_axis_on(bool is);
+ //Derived& title_color(const svg_color& col)
+ //Derived& background_color(const svg_color& col)
+ //Derived& legend_background_color(const svg_color& col)
+ //Derived& legend_border_color(const svg_color& col)
+ //Derived& background_border_color(const svg_color& col)
+ //Derived& plot_background_color(const svg_color& col)
+ //Derived& x_axis_color(const svg_color& col)
+ //Derived& y_axis_color(const svg_color& col)
+ //Derived& x_label_color(const svg_color& col)
+ //Derived& x_label_color(const svg_color& col)
+ //Derived& y_label_color(const svg_color& col)
+ //Derived& x_major_tick_color(const svg_color& col)
+ //Derived& x_minor_tick_color(const svg_color& col)
+ //Derived& x_major_grid_color(const svg_color& col)
+ //Derived& x_major_grid_width(unsigned int w)
+ //Derived& x_minor_grid_color(const svg_color& col)
+ //Derived& x_minor_grid_width(unsigned int w)
+ //Derived& x_axis_width(unsigned int width)
+ //Derived& x_label(const std::string& str)
+ //Derived& x_label_units(const std::string& str)
+ //Derived& y_label(const std::string& str)
+ //Derived& x_major_interval(double inter)
+ //Derived& x_major_tick_length(unsigned int length)
+ //Derived& x_major_tick_width_(unsigned int width)
+ //Derived& x_minor_tick_length_(unsigned int length)
+ //Derived& x_minor_tick_width_(unsigned)
+ //Derived& x_major_tick(double d) int width)
+ //Derived& x_num_minor_ticks(unsigned int num)
+ //Derived& x_range(double min_x, double max_x)
+ //Derived& x_minimum(double min_x)
+ //Derived& x_maximum(double max_x)
+ //Derived& load_stylesheet(const std::string& file)
+ // svg& get_svg()
+
+ // Shapes and glyphs need BOTH fill and stroke to be set.
+ // Both are usually the same in this application.
+ // If both are set, stroke is considered 'more important',
+ // and so is returned by get functions.
+
+
+ // Member functions to set plot options.
+ // All return derived() == *this to permit chaining.
+
+ //-------------------------------------------------------
+
+ Derived& image_size(unsigned int x, unsigned int y)
+ { // Might put default sizes here?
+ // Check on sanity of these values?
+ derived().image.image_size(x, y);
+ return derived();
+ }
- void draw_x_label()
- {
- // color is set in constructor.
- //image.get_g_element(detail::PLOT_X_LABEL).style().stroke_color(black);
- // and using y_label_color(color)
-
- std::string label = derived().x_label_info.text(); // x_axis label, and optional units.
- if (derived().use_x_label_units && (derived().x_units_info.text() != ""))
- { // Append the units, if any, providing brackets ().
- label += " (" + derived().x_units_info.text() + ")";
- }
- // Simplest to start from the bottom of the image.
- // and move up to give enough space for the X-axis label.
-
- double y = derived().image.y_size(); // bottom edge of image.
- y -= derived().x_label_font_size(); // Up enough for a space underneath label.
- derived().image.get_g_element(PLOT_X_LABEL).push_back(new text_element(
- ( // x position relative to the x-axis which is middle of plot window.
- derived().plot_x2 + derived().plot_x1) / 2, // x coordinate - middle.
- y, // Up from image bottom edge.
- label,
- derived().x_label_font_size(),
- derived().x_label_font_family(), "", "", "", "", center_align, horizontal)
- );
- } // void draw_x_label()
-
- // TODO split into adjust_limit(double& x) and call twice?,
- // and TODO use to check 1-D for limit values too?
- void adjust_limits(double& x, double& y)
- { // If value reaches limit of max, min, infinity,
- // use the appropriate plot min or max.
- if(detail::limit_max(x))
- {
- x = derived().plot_x2;
- }
- if(detail::limit_max(y))
- {
- y = derived().plot_y1;
- }
- if(detail::limit_min(x))
- {
- x = derived().plot_x1;
- }
- if(detail::limit_min(y))
- {
- y = derived().plot_y1;
- }
- // If value is NaN, use zero instead.
- // TODO Do we want/get a different color or shape for NaNs??
- if(detail::limit_NaN(x))
- {
- x = 0;
- transform_x(x);
- }
- if(detail::limit_NaN(y))
- {
- y = 0;
- transform_y(y);
- }
- } // void adjust_limits
-
- void draw_plot_point(double x, double y,
- g_element& g_ptr,
- const plot_point_style& sty)
- {
- int size = sty.size_;
- double half_size = size / 2.;
+ unsigned int image_x_size()
+ {
+ return derived().image.x_size();
+ }
- // For 1-D plots, the points do not *need* to be centered on the X-axis,
- // and putting them just above, or sitting on, the X-axis is much clearer.
- // For 2-D plots, the symbol center should, of course,
- // be *centered exactly* on x, y.
- // circle and ellipse are naturally centered on the point.
- // for rect x and y half_size offset centers square on the point.
- // But symbols are in a rectangular box and the offset is different for x & y
- // even assuming that the symbol is centered in the rectangle.
- // the vertical and horizontal ticks are deliberately offset above the axes.
- // TODO Not sure this is fully resolved.
+ Derived& image_x_size(unsigned int i)
+ {
+ derived().image.x_size(i);
+ return derived();
+ }
- switch(sty.shape_) // from enum point_shape none, round, square, point, egg
- {
- case round:
- g_ptr.circle(x, y, half_size);
- break;
- case square:
- g_ptr.rect(x - half_size, y - half_size, size, size);
- break;
- case egg:
- g_ptr.ellipse(x, y, half_size, size * 2.); // Tall thin egg!
- break;
-
- // Offset from center is not an issue with vertical or horizontal ticks.
- // TODO stroke color of line seems to be FILL color, not the stroke color.
- // This is OK-ish, but I'm not sure why.
-
- //svg_color sc = sty.stroke_color;
- //svg_color fc = sty.fill_color;
-
- case vertical_tick: // Especially neat for 1-D points.
- g_ptr.line(x, y, x , y - size); // tick up from axis.
- break;
- case vertical_line:
- g_ptr.line(x, y + size, x , y - size); // line up & down from axis.
- break;
- case horizontal_tick:
- // horizontal_tick is pretty useless for 1-D because the horizontal line is on the X-axis.
- g_ptr.line(x, y, x + size, y ); // tick right from axis.
- break;
- case horizontal_line:
- g_ptr.line(x, y - size, x + size, y ); // line left & right from axis.
- // horizontal_line is pretty useless for 1-D because the horizontal line is on the X-axis.
- break;
-
- case symbol:
- 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
- // boost\math_toolkit\libs\math\doc\sf_and_dist\html4_symbols.qbk,
- // http://www.htmlhelp.com/reference/html40/entities/symbols.html
- // and http://www.alanwood.net/demos/ent4_frame.html
- // The Unicode value in decimal 9830 or hex x2666 must be prefixed with & and terminated with ;
- // for example &x2666; for xml
- // and then enveloped with "" to convert to a std::string, for example: "♦" for diamond.
-
- break;
- case diamond:
- g_ptr.text(x, y, "♦", size, "Lucida Sans Unicode");
- // size / 4. puts bottom tip on the X-axis,
- // size / 2. put center above the X-axis
- // x, y, put on the X-axis - probably what is needed for 2-D plots.
- // diamond, spades, clubs & hearts fill with expected fill_color.
- break;
- case asterisk:
- g_ptr.text(x, y - size / 3., "∗", size, "Lucida Sans Unicode");
- // asterisk is black filled.
- // size /3 puts the bottom tip on the X-axis.
- break;
- case lozenge:
- g_ptr.text(x, y - size / 3., "◊", size, "Lucida Sans Unicode");
- // size / 3 to get tip of lozenge just on the X-axis.
- // lozenge seems not to fill?
- break;
- case club:
- g_ptr.text(x, y, "♣", size, "Lucida Sans Unicode");
- // x, y, puts club just on the X-axis
- break;
- case spade:
- g_ptr.text(x, y, "♠", size, "Lucida Sans Unicode");
- //
- break;
- case heart:
- g_ptr.text(x, y , "♥", size, "Lucida Sans Unicode");
- //
- break;
- case cone: // Pointing down triangle.
- g_ptr.triangle(x - half_size, y - size, x + half_size, y - size, x, y, false);
- // Last point puts the bottom tip of the triangle on the X-axis.
- // This may not be wanted for 2-D.
- break;
- case cross:
- g_ptr.line(x, y + size, x , y - size); // line up & down from axis,
- g_ptr.line(x, y - size, x + size, y ); // & line left & right from axis.
- // Cross is pretty useless for 1-D because the horizontal line is on the X-axis.
-
- break;
- // TODO Other point_shapes do nothing yet.
- }
- } // void draw_plot_point
-
- // -----------------------------------------------------------------
- // Clear Functions.
- // When writing to multiple documents, the contents of the plot
- // may change significantly between. Rather than figuring out what
- // has and has not changed, just erase the contents of the
- // legend, title... in the document and start over.
- // -----------------------------------------------------------------
+ unsigned int image_y_size()
+ {
+ return derived().image.y_size();
+ }
- void clear_all()
- {
- clear_legend();
- clear_background();
- clear_x_axis();
- clear_y_axis();
- clear_title();
- clear_points();
- clear_plot_background();
- clear_grids();
- }
+ Derived& image_y_size(unsigned int i)
+ {
+ derived().image.y_size(i);
+ return derived();
+ }
- void clear_background()
- {
- derived().image.get_g_element(PLOT_BACKGROUND).clear();
- }
+ svg_color background_color()
+ {
+ return derived().image.get_g_element(PLOT_BACKGROUND).style().fill_color();
+ }
- void clear_title()
- {
- derived().image.get_g_element(PLOT_TITLE).clear();
- }
+ Derived& background_border_color(const svg_color& col)
+ {
+ derived().image.get_g_element(PLOT_BACKGROUND).style().stroke_color(col);
+ return derived();
+ }
- void clear_points()
- {
- derived().image.get_g_element(PLOT_DATA_POINTS).clear();
- }
+ svg_color background_border_color()
+ {
+ return derived().image.get_g_element(PLOT_BACKGROUND).style().stroke_color();
+ }
- void clear_plot_background()
- {
- derived().image.get_g_element(PLOT_WINDOW_BACKGROUND).clear();
- }
+ Derived& background_border_width(double w)
+ {
+ derived().image.get_g_element(PLOT_BACKGROUND).style().stroke_width(w);
+ return derived();
+ }
- void clear_legend()
- {
- derived().image.get_g_element(PLOT_LEGEND_BACKGROUND).clear();
- derived().image.get_g_element(PLOT_LEGEND_POINTS).clear();
- derived().image.get_g_element(PLOT_LEGEND_TEXT).clear();
- }
+ double background_border_width()
+ {
+ return derived().image.get_g_element(PLOT_BACKGROUND).style().stroke_width();
+ }
- void clear_x_axis()
- {
- derived().image.get_g_element(PLOT_X_AXIS).clear();
- derived().image.get_g_element(PLOT_X_MINOR_TICKS).clear();
- derived().image.get_g_element(PLOT_X_MAJOR_TICKS).clear();
- derived().image.get_g_element(PLOT_X_LABEL).clear();
- derived().image.get_g_element(PLOT_VALUE_LABELS).clear();
- }
+ Derived& description(const std::string d)
+ { // Writes description to the document(for header as <desc>).
+ derived().image.description(d);
+ return derived();
+ }
- void clear_y_axis()
- {
- derived().image.get_g_element(PLOT_Y_AXIS).clear();
- }
+ const std::string& description()
+ { // Gets description of the document(for header as <desc>).
+ return derived().image.description();
+ }
- void clear_grids()
- {
- derived().image.get_g_element(PLOT_X_MAJOR_GRID).clear();
- derived().image.get_g_element(PLOT_X_MINOR_GRID).clear();
- // TODO don't we need to clear Y grids too??????
- derived().image.get_g_element(PLOT_Y_MAJOR_GRID).clear();
- derived().image.get_g_element(PLOT_Y_MINOR_GRID).clear();
- }
+ Derived& document_title(const std::string d)
+ { // Writes document title to the document(for header as <title>)..
+ derived().image.document_title(d);
+ return derived();
+ }
+ std::string document_title()
+ { // Get document title to the document(for header as <title>)..
+ return derived().image.document_title();
+ }
-private:
- Derived& derived()
- {
- return static_cast<Derived&>(*this); // Why is cast required?
- // error C2440: 'return' : cannot convert from 'boost::svg::detail::axis_plot_frame<Derived>' to 'boost::svg::svg_1d_plot &'
- }
- const Derived& derived()const
- {
- return static_cast<const Derived&>(*this);
- }
-public:
- // Set & get member function Declarations:
- // See svg_fwd.hpp
- // -----------------------------------------------------------------
-
- // Get functions:
- // =========== Image & plot window ==============
- // Derived& image_size(unsigned int x, unsigned int y);
- // unsigned int image_x_size();
- // unsigned int image_y_size()
- // bool plot_window_on()
- // svg_color background_color()
- // svg_color background_border_color()
- // svg_color plot_background_color()
- //
- // std::pair<double, double> plot_window_x()
- // std::pair<double, double> plot_window_y()
-
- // ========= Title & legend ============
- // bool title_on()
- // const std::string title()
- // unsigned int title_font_size()
- // const std::string title_font()
- // svg_color title_color()
- // bool legend_on()
- // const std::string legend_title()
- // svg_color legend_background_color()
- // svg_color legend_border_color()
- // unsigned int legend_title_font_size()
- // ========= Axes & Ticks ============
- // bool x_axis_on()
- // unsigned int x_axis_width()
- // bool x_external_style_on()
- // bool x_ticks_up_on()
- // bool x_ticks_down_on()
- // std::pair<double, double> x_range()
- // double x_minimum()
- // double x_maximum()
- // double x_major_interval()
- // unsigned int x_num_minor__ticks()
- // double x_major_tick()
- // svg_color x_major_tick_color()
- // svg_color x_minor_tick_color()
- // unsigned int x_major_tick_length()
- // unsigned int x_major_tick_width_()
- // unsigned int x_minor_tick_length_()
- // unsigned int x_minor_tick_width_()
- // ========= Labels ============
- // bool x_label_on() // Show X-axis label text.
- // std::string x_label()
- // bool x_label_units_on() //
- // std::string x_label_units() // Show X-axis units text.
- // bool x_major_labels_on()
- // svg_color x_label_color()
- // bool axes_on()
- // svg_color x_axis_color()
- // bool y_axis_on()
- // svg_color y_axis_color()
- // std::string y_label()
- // svg_color y_label_color()
- // ========= grid ============
- // bool x_major_grid_on()
- // bool x_minor_grid_on()
- // unsigned int x_major_grid_width()
- // unsigned int x_minor_grid_width()
- // svg_color x_major_grid_color()
- // svg_color x_minor_grid_color()
-
- // Set functions:
-
-//Derived& image_size(unsigned int x, unsigned int y)
-//Derived& image_x_size(unsigned int x);
-//Derived& image_y_size(unsigned int y);
-
-//Derived& title(const std::string& title)
-
-//Derived& document_title(const std::string&);
-//Derived& description(const std::string&);
-//Derived& copyright_date(const std::string&);
-//Derived& copyright_holder(const std::string&);
-
-//Derived& title_font_size(unsigned int size)
-//Derived& legend_title_font_size(unsigned int size)
-//Derived& legend_on(bool cmd)
-//Derived& plot_window_on(bool cmd)
-//Derived& plot_window_x(unsigned int min_x, unsigned int max_x)
-//Derived& plot_window_y(unsigned int min_y, unsigned int max_y)
-//Derived& x_external_style_on(bool cmd)
-//Derived& x_ticks_up_on(bool cmd)
-//Derived& x_ticks_down_on(bool cmd)
-//Derived& x_label_on(bool cmd)
-//Derived& x_label_units_on(bool cmd)
-//Derived& x_major_labels_on(bool cmd)
-//Derived& title_on(bool cmd)
-//Derived& x_major_grid_on(bool is)
-//Derived& x_minor_grid_on(bool is)
-//Derived& axes_on(bool is)
-//Derived& x_axis_on(bool is)
-//Derived& y_axis_on(bool is);
-//Derived& title_color(const svg_color& col)
-//Derived& background_color(const svg_color& col)
-//Derived& legend_background_color(const svg_color& col)
-//Derived& legend_border_color(const svg_color& col)
-//Derived& background_border_color(const svg_color& col)
-//Derived& plot_background_color(const svg_color& col)
-//Derived& x_axis_color(const svg_color& col)
-//Derived& y_axis_color(const svg_color& col)
-//Derived& x_label_color(const svg_color& col)
-//Derived& x_label_color(const svg_color& col)
-//Derived& y_label_color(const svg_color& col)
-//Derived& x_major_tick_color(const svg_color& col)
-//Derived& x_minor_tick_color(const svg_color& col)
-//Derived& x_major_grid_color(const svg_color& col)
-//Derived& x_major_grid_width(unsigned int w)
-//Derived& x_minor_grid_color(const svg_color& col)
-//Derived& x_minor_grid_width(unsigned int w)
-//Derived& x_axis_width(unsigned int width)
-//Derived& x_label(const std::string& str)
-//Derived& x_label_units(const std::string& str)
-//Derived& y_label(const std::string& str)
-//Derived& x_major_interval(double inter)
-//Derived& x_major_tick_length(unsigned int length)
-//Derived& x_major_tick_width_(unsigned int width)
-//Derived& x_minor_tick_length_(unsigned int length)
-//Derived& x_minor_tick_width_(unsigned)
-//Derived& x_major_tick(double d) int width)
-//Derived& x_num_minor_ticks(unsigned int num)
-//Derived& x_range(double min_x, double max_x)
-//Derived& x_minimum(double min_x)
-//Derived& x_maximum(double max_x)
-//Derived& load_stylesheet(const std::string& file)
-// svg& get_svg()
-
-// Shapes and glyphs need BOTH fill and stroke to be set.
-// Both are usually the same in this application.
-// If both are set, stroke is considered 'more important',
-// and so is returned by get functions.
-
-
- // Member functions to set plot options.
- // All return derived() == *this to permit chaining.
-
- //-------------------------------------------------------
-
- Derived& image_size(unsigned int x, unsigned int y)
- { // Might put default sizes here?
- // Check on sanity of these values?
- derived().image.image_size(x, y);
- return derived();
- }
+ Derived& copyright_holder(const std::string d)
+ { // Writes copyright_holder to the document
+ // (for header as <!-- SVG Plot Copyright Paul A. Bristow 2007 --> )
+ // and as metadata: meta name="copyright" content="Paul A. Bristow" />
+ derived().image.copyright_holder(d);
+ return derived();
+ }
- unsigned int image_x_size()
- {
- return derived().image.x_size();
- }
+ const std::string copyright_holder()
+ { // Get copyright_holder.
+ return derived().image.copyright_holder();
+ }
- Derived& image_x_size(unsigned int i)
- {
- derived().image.x_size(i);
- return derived();
- }
+ Derived& copyright_date(const std::string d)
+ { // Writes copyright_date to the document.
+ // and as metadata <meta name="date" content="2007" />
+ derived().image.copyright_date(d);
+ return derived();
+ }
- unsigned int image_y_size()
- {
- return derived().image.y_size();
- }
+ const std::string copyright_date()
+ { // Get copyright_date.
+ return derived().image.copyright_date();
+ }
- Derived& image_y_size(unsigned int i)
- {
- derived().image.y_size(i);
- return derived();
- }
+ Derived& license(std::string repro = "permits",
+ std::string distrib = "permits",
+ std::string attrib = "requires",
+ std::string commercial = "permits")
+ { // Might check these are "permits", "requires", or "prohibits"?
+ derived().image.license(repro, distrib, attrib, commercial);
+ return derived();
+ }
- svg_color background_color()
- {
- return derived().image.get_g_element(PLOT_BACKGROUND).style().fill_color();
- }
+ const bool license_on()
+ {
+ return derived().image.is_license();
+ }
- Derived& background_border_color(const svg_color& col)
- {
- derived().image.get_g_element(PLOT_BACKGROUND).style().stroke_color(col);
- return derived();
- }
+ const std::string license_reproduction()
+ { // Get copyright_date.
+ return derived().image.reproduction();
+ }
- svg_color background_border_color()
- {
- return derived().image.get_g_element(PLOT_BACKGROUND).style().stroke_color();
- }
+ const std::string license_distribution()
+ { // Get copyright_date.
+ return derived().image.distribution();
+ }
- Derived& background_border_width(double w)
- {
- derived().image.get_g_element(PLOT_BACKGROUND).style().stroke_width(w);
- return derived();
- }
+ const std::string license_attribution()
+ { // Get copyright_date.
+ return derived().image.attribution();
+ }
- double background_border_width()
- {
- return derived().image.get_g_element(PLOT_BACKGROUND).style().stroke_width();
- }
+ const std::string license_commercialuse()
+ { // Get copyright_date.
+ return derived().image.commercialuse();
+ }
- Derived& description(const std::string d)
- { // Writes description to the document(for header as <desc>).
- derived().image.description(d);
- return derived();
- }
-
- const std::string& description()
- { // Gets description of the document(for header as <desc>).
- return derived().image.description();
- }
-
- Derived& document_title(const std::string d)
- { // Writes document title to the document(for header as <title>)..
- derived().image.document_title(d);
- return derived();
- }
- std::string document_title()
- { // Get document title to the document(for header as <title>)..
- return derived().image.document_title();
- }
-
- Derived& copyright_holder(const std::string d)
- { // Writes copyright_holder to the document
- // (for header as <!-- SVG Plot Copyright Paul A. Bristow 2007 --> )
- // and as metadata: meta name="copyright" content="Paul A. Bristow" />
- derived().image.copyright_holder(d);
- return derived();
- }
-
- const std::string copyright_holder()
- { // Get copyright_holder.
- return derived().image.copyright_holder();
- }
-
- Derived& copyright_date(const std::string d)
- { // Writes copyright_date to the document.
- // and as metadata <meta name="date" content="2007" />
- derived().image.copyright_date(d);
- return derived();
- }
-
- const std::string copyright_date()
- { // Get copyright_date.
- return derived().image.copyright_date();
- }
-
- Derived& license(std::string repro = "permits",
- std::string distrib = "permits",
- std::string attrib = "requires",
- std::string commercial = "permits")
- { // Might check these are "permits", "requires", or "prohibits"?
- derived().image.license(repro, distrib, attrib, commercial);
- return derived();
- }
+ Derived& coord_precision(int digits)
+ { // Precision of coordinates in decimal digits (default 3).
+ derived().image.coord_precision(digits);
+ return derived();
+ }
- const bool license_on()
- {
- return derived().image.is_license();
- }
+ int coord_precision()
+ { //
+ return derived().image.coord_precision();
+ }
- const std::string license_reproduction()
- { // Get copyright_date.
- return derived().image.reproduction();
- }
-
- const std::string license_distribution()
- { // Get copyright_date.
- return derived().image.distribution();
- }
-
- const std::string license_attribution()
- { // Get copyright_date.
- return derived().image.attribution();
- }
-
- const std::string license_commercialuse()
- { // Get copyright_date.
- return derived().image.commercialuse();
- }
-
- Derived& coord_precision(int digits)
- { // Precision of coordinates in decimal digits (default 3).
- derived().image.coord_precision(digits);
- return derived();
- }
-
- int coord_precision()
- { //
- return derived().image.coord_precision();
- }
-
- Derived& x_value_precision(int digits)
- { // Precision of X tick label values in decimal digits (default 3).
- derived().x_value_precision_ = digits;
- return derived();
- }
-
- int x_value_precision()
- { //
- return derived().x_value_precision_;
- }
+ Derived& x_value_precision(int digits)
+ { // Precision of X tick label values in decimal digits (default 3).
+ derived().x_value_precision_ = digits;
+ return derived();
+ }
- const std::string title()
- {
- return derived().title_info.text();
- }
+ int x_value_precision()
+ { //
+ return derived().x_value_precision_;
+ }
- Derived& title_font_size(unsigned int i)
- {
- derived().title_info.font_size(i);
- return derived();
- }
+ const std::string title()
+ {
+ return derived().title_info.text();
+ }
- unsigned int title_font_size()
- {
- return derived().title_info.font_size();
- }
+ Derived& title_font_size(unsigned int i)
+ {
+ derived().title_info.font_size(i);
+ return derived();
+ }
- Derived& title_font_family(const std::string& family)
- {
- derived().title_info.font_family(family);
- return derived();
- }
+ unsigned int title_font_size()
+ {
+ return derived().title_info.font_size();
+ }
- const std::string& title_font_family()
- {
- return derived().title_info.font_family();
- }
+ Derived& title_font_family(const std::string& family)
+ {
+ derived().title_info.font_family(family);
+ return derived();
+ }
- Derived& title_font_style(const std::string& style)
- {
- derived().title_info.font_style(style);
- return derived();
- }
+ const std::string& title_font_family()
+ {
+ return derived().title_info.font_family();
+ }
- const std::string& title_font_style()
- {
- return derived().title_info.font_style();
- }
+ Derived& title_font_style(const std::string& style)
+ {
+ derived().title_info.font_style(style);
+ return derived();
+ }
- Derived& title_font_weight(const std::string& weight)
- {
- derived().title_info.font_weight(weight);
- return derived();
- }
+ const std::string& title_font_style()
+ {
+ return derived().title_info.font_style();
+ }
- const std::string& title_font_weight()
- {
- return derived().title_info.font_weight();
- }
+ Derived& title_font_weight(const std::string& weight)
+ {
+ derived().title_info.font_weight(weight);
+ return derived();
+ }
- Derived& legend_font_weight(const std::string& weight)
- {
- derived().legend_header_.font_weight(weight);
- return derived();
- }
+ const std::string& title_font_weight()
+ {
+ return derived().title_info.font_weight();
+ }
- const std::string& legend_font_weight()
- {
- return derived().legend_header_.font_weight();
- }
+ Derived& legend_font_weight(const std::string& weight)
+ {
+ derived().legend_header_.font_weight(weight);
+ return derived();
+ }
- Derived& title_font_stretch(const std::string& stretch)
- {
- derived().title_info.font_stretch(stretch);
- return derived();
- }
+ const std::string& legend_font_weight()
+ {
+ return derived().legend_header_.font_weight();
+ }
- const std::string& title_font_stretch()
- {
- return derived().title_info.font_stretch();
- }
+ Derived& title_font_stretch(const std::string& stretch)
+ {
+ derived().title_info.font_stretch(stretch);
+ return derived();
+ }
- Derived& title_font_decoration(const std::string& decoration)
- {
- derived().title_info.font_decoration(decoration);
- return derived();
- }
+ const std::string& title_font_stretch()
+ {
+ return derived().title_info.font_stretch();
+ }
- const std::string& title_font_decoration()
- {
- return derived().title_info.font_decoration();
- }
+ Derived& title_font_decoration(const std::string& decoration)
+ {
+ derived().title_info.font_decoration(decoration);
+ return derived();
+ }
- Derived& title_font_rotation(int rotate)
- { // Degrees (0 to 360).
- derived().title_info.font_rotation(rotate);
- return derived();
- }
+ const std::string& title_font_decoration()
+ {
+ return derived().title_info.font_decoration();
+ }
- int title_font_rotation()
- {
- return derived().title_info.font_rotation();
- }
+ Derived& title_font_rotation(int rotate)
+ { // Degrees (0 to 360).
+ derived().title_info.font_rotation(rotate);
+ return derived();
+ }
- Derived& title_font_alignment(align_style alignment)
- {
- derived().title_info.font_alignment(alignment);
- return derived();
- }
+ int title_font_rotation()
+ {
+ return derived().title_info.font_rotation();
+ }
- align_style title_font_alignment()
- {
- return derived().title_info.font_alignment();
- }
+ Derived& title_font_alignment(align_style alignment)
+ {
+ derived().title_info.font_alignment(alignment);
+ return derived();
+ }
- Derived& legend_width(double width)
- {
- derived().legend_width_ = width;
- return derived();
- }
+ align_style title_font_alignment()
+ {
+ return derived().title_info.font_alignment();
+ }
- double legend_width()
- {
- return derived().legend_width_;
- }
+ Derived& legend_width(double width)
+ {
+ derived().legend_width_ = width;
+ return derived();
+ }
- Derived& legend_title(const std::string title)
- {
- derived().legend_header_.text(title);
- return derived();
- }
+ double legend_width()
+ {
+ return derived().legend_width_;
+ }
- const std::string legend_title()
- {
- return derived().legend_header_.text();
- }
+ Derived& legend_title(const std::string title)
+ {
+ derived().legend_header_.text(title);
+ return derived();
+ }
- Derived& legend_font_family(const std::string& family)
- {
- derived().legend_header_.font_family(family);
- return derived();
- }
+ const std::string legend_title()
+ {
+ return derived().legend_header_.text();
+ }
- const std::string& legend_font_family()
- {
- return derived().legend_header_.font_family();
- }
+ Derived& legend_font_family(const std::string& family)
+ {
+ derived().legend_header_.font_family(family);
+ return derived();
+ }
- Derived& legend_title_font_size(unsigned int size)
- {
- derived().legend_header_.font_size(size);
- return derived();
- }
+ const std::string& legend_font_family()
+ {
+ return derived().legend_header_.font_family();
+ }
- unsigned int legend_title_font_size()
- {
- return derived().legend_header_.font_size();
- }
+ Derived& legend_title_font_size(unsigned int size)
+ {
+ derived().legend_header_.font_size(size);
+ return derived();
+ }
- Derived& legend_top_left(double x, double y)
- { // Position of top left of legend box (svg coordinates).
- // Bottom right is controlled by contents, so cannot set it.
- if((x < 0) || (x > derived().image.x_size()) || (y < 0) || (y > derived().image.y_size()))
- {
- throw std::runtime_error("Illegal legend box position.");
- }
- derived().legend_x1_ = x;
- derived().legend_y1_ = y;
- return derived();
- }
-
- std::pair<double, double> legend_top_left()
- {// Top left of legend box
- std::pair<double, double> r;
- r.first = derived().legend_x1_;
- r.second = derived().legend_y1_;
- return r;
- }
-
- std::pair<double, double> legend_bottom_right()
- {// Top left of legend box
- std::pair<double, double> r;
- r.first = derived().legend_x2_;
- r.second = derived().legend_y2_;
- return r;
- }
+ unsigned int legend_title_font_size()
+ {
+ return derived().legend_header_.font_size();
+ }
- Derived& line_on(bool is)
- {
- derived().use_line = is;
- return derived();
- }
+ Derived& legend_top_left(double x, double y)
+ { // Position of top left of legend box (svg coordinates).
+ // Bottom right is controlled by contents, so cannot set it.
+ if((x < 0) || (x > derived().image.x_size()) || (y < 0) || (y > derived().image.y_size()))
+ {
+ throw std::runtime_error("Illegal legend box position.");
+ }
+ derived().legend_left_ = x;
+ derived().legend_top_ = y;
+ return derived();
+ }
- bool line_on()
- {
- return derived().use_line;
- }
+ std::pair<double, double> legend_top_left()
+ {// Top left of legend box.
+ std::pair<double, double> r;
+ r.first = derived().legend_left_;
+ r.second = derived().legend_top_;
+ return r;
+ }
- Derived& legend_on(bool cmd)
- {
- derived().use_legend = cmd;
- if(cmd)
- {
- derived().image.get_g_element(detail::PLOT_LEGEND_BACKGROUND)
- .style().fill_color(white)
- .stroke_color(black);
- }
- return derived();
- }
+ std::pair<double, double> legend_bottom_right()
+ {// BOttom right of legend box.
+ std::pair<double, double> r;
+ r.first = derived().legend_right_;
+ r.second = derived().legend_bottom_;
+ return r;
+ }
- bool legend_on()
- {
- return derived().use_legend;
- }
+ Derived& line_on(bool is)
+ {
+ derived().use_line = is;
+ return derived();
+ }
- Derived& plot_window_on(bool cmd)
- {
- derived().use_plot_window_ = cmd;
+ bool line_on()
+ {
+ return derived().use_line;
+ }
- if(cmd)
- { // set plot window color and border color.
- // TODO - allow user to change these.
- derived().image.get_g_element(detail::PLOT_WINDOW_BACKGROUND)
- .style().fill_color(white)
- .stroke_color(black);
- }
- return derived();
- }
+ Derived& legend_on(bool cmd)
+ {
+ derived().use_legend = cmd;
+ if(cmd)
+ {
+ derived().image.get_g_element(detail::PLOT_LEGEND_BACKGROUND)
+ .style().fill_color(white)
+ .stroke_color(black);
+ }
+ return derived();
+ }
- bool plot_window_on()
- {
- return derived().use_plot_window_;
- }
+ bool legend_on()
+ {
+ return derived().use_legend;
+ }
- Derived& plot_border_color(const svg_color& col)
- {
- derived().image.get_g_element(detail::PLOT_WINDOW_BACKGROUND).style().stroke_color(col);
- return derived();
- }
-
- svg_color plot_border_color()
- {
- return derived().image.get_g_element(detail::PLOT_WINDOW_BACKGROUND).style().stroke_color();
- }
+ Derived& legend_place(legend_places l)
+ {
+ derived().legend_place_ = l;
+ return derived();
+ }
- double plot_border_width()
- {
- return derived().image.get_g_element(detail::PLOT_WINDOW_BACKGROUND).style().stroke_width();
- }
+ legend_places legend_place()
+ {
+ return derived().legend_place_;
+ }
- Derived& plot_border_width(double w)
- {
- derived().image.get_g_element(detail::PLOT_WINDOW_BACKGROUND).style().stroke_width(w);
- return derived();
- }
+ bool legend_outside()
+ {
+ return derived().use_outside_legend_;
+ }
+ Derived& plot_window_on(bool cmd)
+ {
+ derived().use_plot_window_ = cmd;
- Derived& border_margin(double w)
- {
- derived().border_margin_ = w;
- return derived();
- }
+ if(cmd)
+ { // set plot window color and border color.
+ // TODO - allow user to change these.
+ derived().image.get_g_element(detail::PLOT_WINDOW_BACKGROUND)
+ .style().fill_color(white)
+ .stroke_color(black);
+ }
+ derived().legend_place_ = outside_right;
+ return derived();
+ }
- double border_margin()
- {
- return derived().border_margin_;
- }
+ bool plot_window_on()
+ {
+ return derived().use_plot_window_;
+ }
- Derived& border_width(double w)
- {
- derived().border_width_ = w;
- return derived();
- }
+ Derived& plot_border_color(const svg_color& col)
+ {
+ derived().image.get_g_element(detail::PLOT_WINDOW_BACKGROUND).style().stroke_color(col);
+ return derived();
+ }
- double border_width()
- {
- return derived().border_width_;
- }
+ svg_color plot_border_color()
+ {
+ return derived().image.get_g_element(detail::PLOT_WINDOW_BACKGROUND).style().stroke_color();
+ }
- Derived& plot_window_x(double min_x, double max_x)
- { // This is normally calculated from other plot values.
- if(max_x <= min_x)
- {
- throw std::runtime_error("plot_window_x: X range: x_max < x_min");
- }
- derived().plot_x1 = min_x;
- derived().plot_x2 = max_x;
- return derived();
- }
-
- Derived& plot_window_y(double min_y, double max_y)
- { // This is normally calculated from other plot values.
- if(max_y <= min_y)
- {
- throw std::runtime_error("plot_window_y : Y range: y_max < y_min");
- }
- derived().plot_y1 = min_y;
- derived().plot_y2 = max_y;
- return derived();
- }
+ double plot_border_width()
+ {
+ return derived().image.get_g_element(detail::PLOT_WINDOW_BACKGROUND).style().stroke_width();
+ }
+
+ Derived& plot_border_width(double w)
+ {
+ derived().image.get_g_element(detail::PLOT_WINDOW_BACKGROUND).style().stroke_width(w);
+ return derived();
+ }
+
+ Derived& border_margin(double w)
+ {
+ derived().border_margin_ = w;
+ return derived();
+ }
+
+ double border_margin()
+ {
+ return derived().border_margin_;
+ }
+
+ Derived& border_width(double w)
+ {
+ derived().border_width_ = w;
+ return derived();
+ }
+
+ double border_width()
+ {
+ return derived().border_width_;
+ }
+
+ Derived& plot_window_x(double min_x, double max_x)
+ { // This is normally calculated from other plot values.
+ if(max_x <= min_x)
+ {
+ throw std::runtime_error("plot_window_x: X range: x_max < x_min");
+ }
+ derived().plot_x1 = min_x;
+ derived().plot_x2 = max_x;
+ return derived();
+ }
+
+ Derived& plot_window_y(double min_y, double max_y)
+ { // This is normally calculated from other plot values.
+ if(max_y <= min_y)
+ {
+ throw std::runtime_error("plot_window_y : Y range: y_max < y_min");
+ }
+ derived().plot_y1 = min_y;
+ derived().plot_y2 = max_y;
+ return derived();
+ }
+
+ std::pair<double, double> plot_window_x()
+ {
+ std::pair<double, double> r;
+ r.first = derived().plot_x1;
+ r.second = derived().plot_x2;
+ return r;
+ }
+
+ double plot_window_x_left()
+ {
+ return derived().plot_x1;
+ }
+ double plot_window_x_right()
+ {
+ return derived().plot_x2;
+ }
+ double plot_window_y_top()
+ {
+ return derived().plot_y1;
+ }
+ double plot_window_y_bottom()
+ {
+ return derived().plot_y2;
+ }
+
+ std::pair<double, double> plot_window_y()
+ {
+ std::pair<double, double> r;
+ r.first = derived().plot_y1;
+ r.second = derived().plot_y2;
+ return r;
+ }
+
+ double x_minor_interval()
+ {
+ return derived().x_minor_interval_; // interval
+ }
+
+ double y_minor_interval()
+ {
+ return derived().y_minor_interval_; // interval
+ }
+
+ Derived& x_ticks_up_on(bool cmd)
+ {
+ derived().use_up_ticks = cmd;
+ return derived();
+ }
+
+ bool x_ticks_up_on()
+ {
+ return derived().use_up_ticks;
+ }
+
+ Derived& x_ticks_down_on(bool cmd)
+ {
+ derived().use_down_ticks = cmd;
+ return derived();
+ }
+
+ bool x_ticks_down_on()
+ {
+ return derived().use_down_ticks;
+ }
+ // Only need y_ticks_left_on & y_ticks_right_on in 2D
+
+ Derived& x_label_on(bool cmd)
+ { // Show X-axis label text, or not.
+ derived().use_x_label = cmd;
+ return derived();
+ }
+
+ bool x_label_on()
+ {
+ return derived().use_x_label;
+ }
+
+ Derived& x_label_font_size(unsigned int i)
+ {
+ derived().x_label_info.font_size(i);
+ return derived();
+ }
+
+ unsigned int x_label_font_size()
+ {
+ return derived().x_label_info.font_size();
+ }
+
+ Derived& x_value_font_size(unsigned int i)
+ {
+ derived().x_value_value.font_size(i);
+ return derived();
+ }
+
+ unsigned int x_value_font_size()
+ {
+ return derived().x_value_value.font_size();
+ }
+
+ Derived& x_label_font_family(const std::string& family)
+ {
+ derived().x_label_info.font_family(family);
+ return derived();
+ }
+
+ const std::string& x_label_font_family()
+ {
+ return derived().x_label_info.font_family();
+ }
+
+ Derived& x_value_ioflags(int flags)
+ { // IO flags of X tick label values (default 0X201).
+ derived().x_value_ioflags_ = flags;
+ return derived();
+ }
+
+ int x_value_ioflags()
+ { // ALL stream ioflags for control of format of X value labels.
+ return derived().x_value_ioflags_;
+ }
+
+ Derived& title(const std::string title)
+ { // Plot title.
+ derived().title_info.text(title);
+ return derived();
+ }
+
+ Derived& x_axis_label_color(const svg_color& col)
+ { // Set BOTH stroke and fill to the same color.
+ derived().image.get_g_element(detail::PLOT_X_LABEL).style().fill_color(col);
+ derived().image.get_g_element(detail::PLOT_X_LABEL).style().stroke_color(col);
+ return *this;
+ }
+
+ svg_color x_axis_label_color()
+ { // But only return the stroke color.
+ return derived().image.get_g_element(detail::PLOT_X_LABEL).style().stroke_color();
+ }
+
+ Derived& x_axis_value_color(const svg_color& col)
+ { // Set BOTH stroke and fill to the same color.
+ derived().image.get_g_element(detail::PLOT_VALUE_LABELS).style().fill_color(col);
+ derived().image.get_g_element(detail::PLOT_VALUE_LABELS).style().stroke_color(col);
+ return *this;
+ }
+
+ svg_color x_axis_value_color()
+ { // But only return the stroke color.
+ return derived().image.get_g_element(detail::PLOT_VALUE_LABELS).style().stroke_color();
+ }
+
+ Derived& x_ticks_on_plot_window_on(bool cmd)
+ { // External style.
+ derived().use_x_ticks_on_plot_window_ = cmd;
+ return derived();
+ }
+
+ bool x_ticks_on_plot_window_on()
+ { // External style = true.
+ return derived().use_x_ticks_on_plot_window_;
+ }
- std::pair<double, double> plot_window_x()
- {
- std::pair<double, double> r;
- r.first = derived().plot_x1;
- r.second = derived().plot_x2;
- return r;
- }
+ Derived& x_label_units_on(bool cmd)
+ {
+ derived().use_x_label_units = cmd;
+ return derived();
+ }
- double plot_window_x_left()
- {
- return derived().plot_x1;
- }
- double plot_window_x_right()
- {
- return derived().plot_x2;
- }
- double plot_window_y_top()
- {
- return derived().plot_y1;
- }
- double plot_window_y_bottom()
- {
- return derived().plot_y2;
- }
+ bool x_label_units_on()
+ {
+ return derived().use_x_label_units;
+ }
- std::pair<double, double> plot_window_y()
- {
- std::pair<double, double> r;
- r.first = derived().plot_y1;
- r.second = derived().plot_y2;
- return r;
- }
+ Derived& x_major_labels_on(bool cmd)
+ {
+ derived().use_x_major_labels = cmd;
+ return derived();
+ }
- double x_minor_interval()
- {
- return derived().x_minor_interval_; // interval
- }
+ bool x_major_labels_on()
+ {
+ return derived().use_x_major_labels;
+ }
- double y_minor_interval()
- {
- return derived().y_minor_interval_; // interval
- }
+ Derived& x_major_label_rotation(int rot)
+ {
+ derived().x_label_rotation_ = rot;
+ return derived();
+ }
- Derived& x_ticks_up_on(bool cmd)
- {
- derived().use_up_ticks = cmd;
- return derived();
- }
+ int x_major_label_rotation()
+ {
+ return derived().x_label_rotation_;
+ }
- bool x_ticks_up_on()
- {
- return derived().use_up_ticks;
- }
+ Derived& title_on(bool cmd)
+ {
+ derived().use_title = cmd;
+ return derived();
+ }
- Derived& x_ticks_down_on(bool cmd)
- {
- derived().use_down_ticks = cmd;
- return derived();
- }
+ bool title_on()
+ {
+ return derived().use_title;
+ }
- bool x_ticks_down_on()
- {
- return derived().use_down_ticks;
- }
- // Only need y_ticks_left_on & y_ticks_right_on in 2D
-
- Derived& x_label_on(bool cmd)
- { // Show X-axis label text, or not.
- derived().use_x_label = cmd;
- return derived();
- }
+ Derived& x_major_grid_on(bool is)
+ {
+ derived().use_x_major_grid_ = is;
+ return derived();
+ }
- bool x_label_on()
- {
- return derived().use_x_label;
- }
+ bool x_major_grid_on()
+ {
+ return derived().use_x_major_grid_;
+ }
- Derived& x_label_font_size(unsigned int i)
- {
- derived().x_label_info.font_size(i);
- return derived();
- }
+ Derived& x_minor_grid_on(bool is)
+ {
+ derived().use_x_minor_grid_ = is;
+ return derived();
+ }
- unsigned int x_label_font_size()
- {
- return derived().x_label_info.font_size();
- }
+ bool x_minor_grid_on()
+ {
+ return derived().use_x_minor_grid_;
+ }
- Derived& x_value_font_size(unsigned int i)
- {
- derived().x_value_value.font_size(i);
- return derived();
- }
+ Derived& axes_on(bool is)
+ { // Draw *both* x and y axes (note plural).
+ derived().use_x_axis_lines_ = is;
+ derived().use_y_axis_lines_ = is;
+ return derived();
+ }
- unsigned int x_value_font_size()
- {
- return derived().x_value_value.font_size();
- }
+ bool axes_on()
+ { // Used X in preference to Y for 1D, but now require *both* x and y axis on.
+ return derived().use_x_axis_lines_ && derived().use_y_axis_lines_;
+ }
- Derived& x_label_font_family(const std::string& family)
- {
- derived().x_label_info.font_family(family);
- return derived();
- }
+ Derived& x_axis_on(bool is)
+ { // Draw a horizontal x_axis line.
+ derived().use_x_axis_lines_ = is;
+ return derived();
+ }
- const std::string& x_label_font_family()
- {
- return derived().x_label_info.font_family();
- }
+ bool x_axis_on()
+ { // Use X in preference to Y for 1D
+ return derived().use_x_axis_lines_;
+ }
- Derived& x_value_ioflags(int flags)
- { // IO flags of X tick label values (default 0X201).
- derived().x_value_ioflags_ = flags;
- return derived();
- }
-
- int x_value_ioflags()
- { // ALL stream ioflags for control of format of X value labels.
- return derived().x_value_ioflags_;
- }
-
- Derived& title(const std::string title)
- { // Plot title.
- derived().title_info.text(title);
- return derived();
- }
-
-
- Derived& x_axis_label_color(const svg_color& col)
- { // Set BOTH stroke and fill to the same color.
- derived().image.get_g_element(detail::PLOT_X_LABEL).style().fill_color(col);
- derived().image.get_g_element(detail::PLOT_X_LABEL).style().stroke_color(col);
- return *this;
- }
-
- svg_color x_axis_label_color()
- { // But only return the stroke color.
- return derived().image.get_g_element(detail::PLOT_X_LABEL).style().stroke_color();
- }
-
- Derived& x_axis_value_color(const svg_color& col)
- { // Set BOTH stroke and fill to the same color.
- derived().image.get_g_element(detail::PLOT_VALUE_LABELS).style().fill_color(col);
- derived().image.get_g_element(detail::PLOT_VALUE_LABELS).style().stroke_color(col);
- return *this;
- }
-
- svg_color x_axis_value_color()
- { // But only return the stroke color.
- return derived().image.get_g_element(detail::PLOT_VALUE_LABELS).style().stroke_color();
- }
-
- Derived& x_ticks_on_plot_window_on(bool cmd)
- { // External style.
- derived().use_x_ticks_on_plot_window_ = cmd;
- return derived();
- }
-
- bool x_ticks_on_plot_window_on()
- { // External style = true.
- return derived().use_x_ticks_on_plot_window_;
- }
+ Derived& y_axis_on(bool is)
+ {// Draw a vertical y_axis line.
+ derived().use_y_axis_lines_ = is;
+ return derived();
+ }
- Derived& x_label_units_on(bool cmd)
- {
- derived().use_x_label_units = cmd;
- return derived();
- }
+ bool y_axis_on()
+ { // Should be always false for 1D.
+ return derived().use_y_axis_lines_;
+ }
- bool x_label_units_on()
- {
- return derived().use_x_label_units;
- }
+ // enums like PLOT_TITLE provide a std:string like "title"
+ // colors .stroke_color, .stroke_width and font are set in the appropriate g_element.
- Derived& x_major_labels_on(bool cmd)
- {
- derived().use_x_major_labels = cmd;
- return derived();
- }
+ Derived& title_color(const svg_color& col)
+ {
+ derived().image.get_g_element(PLOT_TITLE).style().stroke_color(col);
+ derived().image.get_g_element(PLOT_TITLE).style().fill_color(col);
+ return derived();
+ }
- bool x_major_labels_on()
- {
- return derived().use_x_major_labels;
- }
+ svg_color title_color()
+ { // Function title_color sets both fill and stroke,
+ // but stroke (outside) is considered 'more important'.
+ return derived().image.get_g_element(PLOT_TITLE).style().stroke_color();
+ }
- Derived& x_major_label_rotation(int rot)
- {
- derived().x_label_rotation_ = rot;
- return derived();
- }
+ Derived& title_font_width(double width)
+ { // width of text is effectively the boldness
+ derived().image.get_g_element(PLOT_TITLE).style().stroke_width(width);
+ return derived();
+ }
- int x_major_label_rotation()
- {
- return derived().x_label_rotation_;
- }
+ double title_font_width()
+ {
+ return derived().image.get_g_element(PLOT_TITLE).style().stroke_width();
+ }
- Derived& title_on(bool cmd)
- {
- derived().use_title = cmd;
- return derived();
- }
+ Derived& legend_color(const svg_color& col)
+ {
+ derived().image.get_g_element(PLOT_LEGEND_TEXT).style().fill_color(col);
+ derived().image.get_g_element(PLOT_LEGEND_TEXT).style().stroke_color(col);
+ return derived();
+ }
- bool title_on()
- {
- return derived().use_title;
- }
+ svg_color legend_color()
+ { // Function legend_color sets both fill and stroke,
+ // but stroke (outside) is considered 'more important'.
+ return derived().image.get_g_element(PLOT_LEGEND_TEXT).style().stroke_color();
+ }
- Derived& x_major_grid_on(bool is)
- {
- derived().use_x_major_grid_ = is;
- return derived();
- }
+ Derived& legend_font_width(double width)
+ { // width of text is effectively the boldness.
+ derived().image.get_g_element(PLOT_LEGEND_TEXT).style().stroke_width(width);
+ return derived();
+ }
- bool x_major_grid_on()
- {
- return derived().use_x_major_grid_;
- }
+ double legend_font_width()
+ {
+ return derived().image.get_g_element(PLOT_LEGEND_TEXT).style().stroke_width();
+ }
- Derived& x_minor_grid_on(bool is)
- {
- derived().use_x_minor_grid_ = is;
- return derived();
- }
+ Derived& background_color(const svg_color& col)
+ {
+ derived().image.get_g_element(PLOT_BACKGROUND).style().fill_color(col);
+ return derived();
+ }
- bool x_minor_grid_on()
- {
- return derived().use_x_minor_grid_;
- }
+ Derived& legend_background_color(const svg_color& col)
+ {
+ derived().image.get_g_element(PLOT_LEGEND_BACKGROUND).style().fill_color(col);
+ return derived();
+ }
- Derived& axes_on(bool is)
- { // Draw *both* x and y axes (note plural).
- derived().use_x_axis_lines_ = is;
- derived().use_y_axis_lines_ = is;
- return derived();
- }
-
- bool axes_on()
- { // Used X in preference to Y for 1D, but now require *both* x and y axis on.
- return derived().use_x_axis_lines_ && derived().use_y_axis_lines_;
- }
-
- Derived& x_axis_on(bool is)
- { // Draw a horizontal x_axis line.
- derived().use_x_axis_lines_ = is;
- return derived();
- }
-
- bool x_axis_on()
- { // Use X in preference to Y for 1D
- return derived().use_x_axis_lines_;
- }
-
- Derived& y_axis_on(bool is)
- {// Draw a vertical y_axis line.
- derived().use_y_axis_lines_ = is;
- return derived();
- }
-
- bool y_axis_on()
- { // Should be always false for 1D.
- return derived().use_y_axis_lines_;
- }
+ svg_color legend_background_color()
+ {
+ return derived().image.get_g_element(PLOT_LEGEND_BACKGROUND).style().fill_color();
+ }
- // enums like PLOT_TITLE provide a std:string like "title"
- // colors .stroke_color, .stroke_width and font are set in the appropriate g_element.
+ Derived& legend_border_color(const svg_color& col)
+ {
+ derived().image.get_g_element(PLOT_LEGEND_BACKGROUND).style().stroke_color(col);
+ return derived();
+ }
- Derived& title_color(const svg_color& col)
- {
- derived().image.get_g_element(PLOT_TITLE).style().stroke_color(col);
- derived().image.get_g_element(PLOT_TITLE).style().fill_color(col);
- return derived();
- }
-
- svg_color title_color()
- { // Function title_color sets both fill and stroke,
- // but stroke (outside) is considered 'more important'.
- return derived().image.get_g_element(PLOT_TITLE).style().stroke_color();
- }
-
- Derived& title_font_width(double width)
- { // width of text is effectively the boldness
- derived().image.get_g_element(PLOT_TITLE).style().stroke_width(width);
- return derived();
- }
+ svg_color legend_border_color()
+ {
+ return derived().image.get_g_element(PLOT_LEGEND_BACKGROUND).style().stroke_color();
+ }
- double title_font_width()
- {
- return derived().image.get_g_element(PLOT_TITLE).style().stroke_width();
- }
+ Derived& plot_background_color(const svg_color& col)
+ {
+ derived().image.get_g_element(PLOT_WINDOW_BACKGROUND).style().fill_color(col);
+ return derived();
+ }
- Derived& legend_color(const svg_color& col)
- {
- derived().image.get_g_element(PLOT_LEGEND_TEXT).style().fill_color(col);
- derived().image.get_g_element(PLOT_LEGEND_TEXT).style().stroke_color(col);
- return derived();
- }
-
- svg_color legend_color()
- { // Function legend_color sets both fill and stroke,
- // but stroke (outside) is considered 'more important'.
- return derived().image.get_g_element(PLOT_LEGEND_TEXT).style().stroke_color();
- }
-
- Derived& legend_font_width(double width)
- { // width of text is effectively the boldness.
- derived().image.get_g_element(PLOT_LEGEND_TEXT).style().stroke_width(width);
- return derived();
- }
+ svg_color plot_background_color()
+ {
+ return derived().image.get_g_element(PLOT_WINDOW_BACKGROUND).style().fill_color();
+ }
- double legend_font_width()
- {
- return derived().image.get_g_element(PLOT_LEGEND_TEXT).style().stroke_width();
- }
+ Derived& x_axis_color(const svg_color& col)
+ { // Note only stroke color is set.
+ derived().image.get_g_element(PLOT_X_AXIS).style().stroke_color(col);
+ return derived();
+ }
- Derived& background_color(const svg_color& col)
- {
- derived().image.get_g_element(PLOT_BACKGROUND).style().fill_color(col);
- return derived();
- }
+ svg_color x_axis_color()
+ {
+ return derived().image.get_g_element(PLOT_X_AXIS).style().stroke_color();
+ }
- Derived& legend_background_color(const svg_color& col)
- {
- derived().image.get_g_element(PLOT_LEGEND_BACKGROUND).style().fill_color(col);
- return derived();
- }
+ Derived& y_axis_color(const svg_color& col)
+ {
+ derived().image.get_g_element(PLOT_Y_AXIS).style().stroke_color(col);
+ return derived();
+ }
- svg_color legend_background_color()
- {
- return derived().image.get_g_element(PLOT_LEGEND_BACKGROUND).style().fill_color();
- }
+ svg_color y_axis_color()
+ {
+ return derived().image.get_g_element(PLOT_Y_AXIS).style().stroke_color();
+ }
- Derived& legend_border_color(const svg_color& col)
- {
- derived().image.get_g_element(PLOT_LEGEND_BACKGROUND).style().stroke_color(col);
- return derived();
- }
+ Derived& x_label_color(const svg_color& col)
+ { // add fill as well PAB Oct 07
+ derived().image.get_g_element(PLOT_X_LABEL).style().fill_color(col);
+ derived().image.get_g_element(PLOT_X_LABEL).style().stroke_color(col);
+ return derived();
+ }
- svg_color legend_border_color()
- {
- return derived().image.get_g_element(PLOT_LEGEND_BACKGROUND).style().stroke_color();
- }
+ Derived& x_label_width(double width)
+ { // width of text is effectively the boldness.
+ x_label_width_ = width;
+ derived().image.get_g_element(PLOT_X_LABEL).style().stroke_width(width);
+ return derived();
+ }
- Derived& plot_background_color(const svg_color& col)
- {
- derived().image.get_g_element(PLOT_WINDOW_BACKGROUND).style().fill_color(col);
- return derived();
- }
+ double x_label_width()
+ {
+ //return x_label_width_;
+ return derived().image.get_g_element(PLOT_X_LABEL).style().stroke_width();
+ }
- svg_color plot_background_color()
- {
- return derived().image.get_g_element(PLOT_WINDOW_BACKGROUND).style().fill_color();
- }
+ svg_color x_label_color()
+ {
+ return derived().image.get_g_element(PLOT_X_LABEL).style().fill_color();
+ }
- Derived& x_axis_color(const svg_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()
- {
- return derived().image.get_g_element(PLOT_X_AXIS).style().stroke_color();
- }
+ Derived& y_label_color(const svg_color& col)
+ {
+ derived().image.get_g_element(PLOT_Y_LABEL).style().fill_color(col);
+ derived().image.get_g_element(PLOT_Y_LABEL).style().stroke_color(col);
+ return derived();
+ }
- Derived& y_axis_color(const svg_color& col)
- {
- derived().image.get_g_element(PLOT_Y_AXIS).style().stroke_color(col);
- return derived();
- }
+ svg_color y_label_color()
+ {
+ return derived().image.get_g_element(PLOT_Y_LABEL).style().fill_color();
+ }
- svg_color y_axis_color()
- {
- return derived().image.get_g_element(PLOT_Y_AXIS).style().stroke_color();
- }
+ Derived& x_major_tick_color(const svg_color& col)
+ {
+ derived().image.get_g_element(PLOT_X_MAJOR_TICKS).style().stroke_color(col);
+ return derived();
+ }
- Derived& x_label_color(const svg_color& col)
- { // add fill as well PAB Oct 07
- derived().image.get_g_element(PLOT_X_LABEL).style().fill_color(col);
- derived().image.get_g_element(PLOT_X_LABEL).style().stroke_color(col);
- return derived();
- }
-
- Derived& x_label_width(double width)
- { // width of text is effectively the boldness.
- x_label_width_ = width;
- derived().image.get_g_element(PLOT_X_LABEL).style().stroke_width(width);
- return derived();
- }
+ svg_color x_major_tick_color()
+ {
+ return derived().image.get_g_element(PLOT_X_MAJOR_TICKS).style().stroke_color();
+ }
- double x_label_width()
- {
- //return x_label_width_;
- return derived().image.get_g_element(PLOT_X_LABEL).style().stroke_width();
- }
+ Derived& x_minor_tick_color(const svg_color& col)
+ {
+ derived().image.get_g_element(PLOT_X_MINOR_TICKS).style().stroke_color(col);
+ return derived();
+ }
- svg_color x_label_color()
- {
- return derived().image.get_g_element(PLOT_X_LABEL).style().fill_color();
- }
+ svg_color x_minor_tick_color()
+ {
+ return derived().image.get_g_element(PLOT_X_MINOR_TICKS).style().stroke_color();
+ }
- Derived& y_label_color(const svg_color& col)
- {
- derived().image.get_g_element(PLOT_Y_LABEL).style().fill_color(col);
- derived().image.get_g_element(PLOT_Y_LABEL).style().stroke_color(col);
- return derived();
- }
+ Derived& x_major_grid_color(const svg_color& col)
+ {
+ derived().image.get_g_element(PLOT_X_MAJOR_GRID).style().stroke_color(col);
+ return derived();
+ }
- svg_color y_label_color()
- {
- return derived().image.get_g_element(PLOT_Y_LABEL).style().fill_color();
- }
+ svg_color x_major_grid_color()
+ {
+ return derived().image.get_g_element(PLOT_X_MAJOR_GRID).style().stroke_color();
+ }
- Derived& x_major_tick_color(const svg_color& col)
- {
- derived().image.get_g_element(PLOT_X_MAJOR_TICKS).style().stroke_color(col);
- return derived();
- }
+ Derived& x_major_grid_width(double w)
+ {
+ derived().image.get_g_element(PLOT_X_MAJOR_GRID).style().stroke_width(w);
+ return derived();
+ }
- svg_color x_major_tick_color()
- {
- return derived().image.get_g_element(PLOT_X_MAJOR_TICKS).style().stroke_color();
- }
+ double x_major_grid_width()
+ {
+ return derived().image.get_g_element(PLOT_X_MAJOR_GRID).style().stroke_width();
+ }
- Derived& x_minor_tick_color(const svg_color& col)
- {
- derived().image.get_g_element(PLOT_X_MINOR_TICKS).style().stroke_color(col);
- return derived();
- }
+ Derived& x_minor_grid_color(const svg_color& col)
+ {
+ derived().image.get_g_element(PLOT_X_MINOR_GRID).style().stroke_color(col);
+ return derived();
+ }
- svg_color x_minor_tick_color()
- {
- return derived().image.get_g_element(PLOT_X_MINOR_TICKS).style().stroke_color();
- }
+ svg_color x_minor_grid_color()
+ {
+ return derived().image.get_g_element(PLOT_X_MINOR_GRID).style().stroke_color();
+ }
- Derived& x_major_grid_color(const svg_color& col)
- {
- derived().image.get_g_element(PLOT_X_MAJOR_GRID).style().stroke_color(col);
- return derived();
- }
+ Derived& x_minor_grid_width(double w)
+ {
+ derived().image.get_g_element(PLOT_X_MINOR_GRID).style().stroke_width(w);
+ return derived();
+ }
- svg_color x_major_grid_color()
- {
- return derived().image.get_g_element(PLOT_X_MAJOR_GRID).style().stroke_color();
- }
+ double x_minor_grid_width()
+ {
+ return derived().image.get_g_element(PLOT_X_MINOR_GRID).style().stroke_width();
+ }
- Derived& x_major_grid_width(double w)
- {
- derived().image.get_g_element(PLOT_X_MAJOR_GRID).style().stroke_width(w);
- return derived();
- }
+ Derived& x_axis_width(double width)
+ {
+ derived().image.get_g_element(PLOT_X_AXIS).style().stroke_width(width);
+ return derived();
+ }
- double x_major_grid_width()
- {
- return derived().image.get_g_element(PLOT_X_MAJOR_GRID).style().stroke_width();
- }
+ double x_axis_width()
+ {
+ return derived().image.get_g_element(PLOT_X_AXIS).style().stroke_width();
+ }
- Derived& x_minor_grid_color(const svg_color& col)
- {
- derived().image.get_g_element(PLOT_X_MINOR_GRID).style().stroke_color(col);
- return derived();
- }
+ Derived& data_lines_width(double width)
+ {
+ derived().image.get_g_element(PLOT_DATA_LINES).style().stroke_width(width);
+ return derived();
+ }
- svg_color x_minor_grid_color()
- {
- return derived().image.get_g_element(PLOT_X_MINOR_GRID).style().stroke_color();
- }
+ double data_lines_width()
+ {
+ return derived().image.get_g_element(PLOT_DATA_LINES).style().stroke_width();
+ }
- Derived& x_minor_grid_width(double w)
- {
- derived().image.get_g_element(PLOT_X_MINOR_GRID).style().stroke_width(w);
- return derived();
- }
+ Derived& x_label(const std::string& str)
+ {
+ derived().x_label_info.text(str);
+ return derived();
+ }
- double x_minor_grid_width()
- {
- return derived().image.get_g_element(PLOT_X_MINOR_GRID).style().stroke_width();
- }
+ std::string x_label()
+ {
+ return derived().x_label_info.text();
+ }
- Derived& x_axis_width(double width)
- {
- derived().image.get_g_element(PLOT_X_AXIS).style().stroke_width(width);
- return derived();
- }
+ Derived& x_label_units(const std::string& str)
+ {
+ derived().x_units_info.text(str);
+ return derived();
+ }
- double x_axis_width()
- {
- return derived().image.get_g_element(PLOT_X_AXIS).style().stroke_width();
- }
+ std::string x_label_units()
+ {
+ return derived().x_units_info.text();
+ }
- Derived& data_lines_width(double width)
- {
- derived().image.get_g_element(PLOT_DATA_LINES).style().stroke_width(width);
- return derived();
- }
+ // y_label not needed in 1D.
+ Derived& y_label(const std::string& str)
+ {
+ derived().y_label_info.text(str);
+ return derived();
+ }
- double data_lines_width()
- {
- return derived().image.get_g_element(PLOT_DATA_LINES).style().stroke_width();
- }
+ std::string y_label()
+ {
+ return derived().y_label_info.text();
+ }
- Derived& x_label(const std::string& str)
- {
- derived().x_label_info.text(str);
- return derived();
- }
+ Derived& y_label_units(const std::string& str)
+ {
+ derived().y_units_info.text(str);
+ return derived();
+ }
- std::string x_label()
- {
- return derived().x_label_info.text();
- }
+ std::string y_label_units()
+ {
+ return derived().y_units_info.text();
+ }
- Derived& x_label_units(const std::string& str)
- {
- derived().x_units_info.text(str);
- return derived();
- }
+ Derived& x_major_interval(double inter)
+ {
+ derived().x_major_interval_ = inter;
+ return derived();
+ }
- std::string x_label_units()
- {
- return derived().x_units_info.text();
- }
+ double x_major_interval()
+ {
+ return derived().x_major_interval_;
+ }
- // y_label not needed in 1D.
- Derived& y_label(const std::string& str)
- {
- derived().y_label_info.text(str);
- return derived();
- }
+ Derived& x_major_tick_length(double length)
+ {
+ derived().x_major_tick_length_ = length;
+ return derived();
+ }
- std::string y_label()
- {
- return derived().y_label_info.text();
- }
+ double x_major_tick_length()
+ {
+ return derived().x_major_tick_length_;
+ }
- Derived& y_label_units(const std::string& str)
- {
- derived().y_units_info.text(str);
- return derived();
- }
+ Derived& x_major_tick_width(double width)
+ {
+ derived().x_major_tick_width_ = width; // Redundant?
+ derived().image.get_g_element(PLOT_X_MAJOR_TICKS).style().stroke_width(width);
+ return derived();
+ }
- std::string y_label_units()
- {
- return derived().y_units_info.text();
- }
+ double x_major_tick_width()
+ {
+ return derived().image.get_g_element(PLOT_X_MAJOR_TICKS).style().stroke_width();
+ }
- Derived& x_major_interval(double inter)
- {
- derived().x_major_interval_ = inter;
- return derived();
- }
+ Derived& x_minor_tick_length(double length)
+ {
+ derived().x_minor_tick_length_ = length;
+ return derived();
+ }
- double x_major_interval()
- {
- return derived().x_major_interval_;
- }
+ double x_minor_tick_length()
+ {
+ return derived().x_minor_tick_length_;
+ }
- Derived& x_major_tick_length(double length)
- {
- derived().x_major_tick_length_ = length;
- return derived();
- }
+ Derived& x_minor_tick_width(double width)
+ {
+ derived().x_minor_tick_width_ = width;
+ derived().image.get_g_element(PLOT_X_MINOR_TICKS).style().stroke_width(width);
+ return derived();
+ }
- double x_major_tick_length()
- {
- return derived().x_major_tick_length_;
- }
+ double x_minor_tick_width()
+ {
+ // return derived().x_minor_tick_width_; // should be the same but store in stroke_width is definitive.
+ return derived().image.get_g_element(PLOT_X_MINOR_TICKS).style().stroke_width();
+ }
- Derived& x_major_tick_width(double width)
- {
- derived().x_major_tick_width_ = width; // Redundant?
- derived().image.get_g_element(PLOT_X_MAJOR_TICKS).style().stroke_width(width);
- return derived();
- }
+ Derived& x_major_tick(double d)
+ { // Interval (Cartesian units) between major ticks.
+ derived().x_major_interval_ = d;
+ }
- double x_major_tick_width()
- {
- return derived().image.get_g_element(PLOT_X_MAJOR_TICKS).style().stroke_width();
- }
+ double x_major_tick()
+ { // Interval (Cartesian units) between major ticks.
+ return derived().x_major_interval_;
+ }
- Derived& x_minor_tick_length(double length)
- {
- derived().x_minor_tick_length_ = length;
- return derived();
- }
+ Derived& x_minor_interval(double interval)
+ { // aka x_minor_tick
+ derived().x_minor_interval_ = interval;
+ return derived();
+ }
- double x_minor_tick_length()
- {
- return derived().x_minor_tick_length_;
- }
+ Derived& x_num_minor_ticks(unsigned int num)
+ {
+ derived().x_num_minor_ticks_ = num;
+ return derived();
+ }
- Derived& x_minor_tick_width(double width)
- {
- derived().x_minor_tick_width_ = width;
- derived().image.get_g_element(PLOT_X_MINOR_TICKS).style().stroke_width(width);
- return derived();
- }
+ unsigned int x_num_minor_ticks()
+ { // NB NOT float or double!
+ return derived().x_num_minor_ticks_;
+ }
- double x_minor_tick_width()
- {
- // return derived().x_minor_tick_width_; // should be the same but store in stroke_width is definitive.
- return derived().image.get_g_element(PLOT_X_MINOR_TICKS).style().stroke_width();
- }
-
- Derived& x_major_tick(double d)
- { // Interval (Cartesian units) between major ticks.
- derived().x_major_interval_ = d;
- }
-
- double x_major_tick()
- { // Interval (Cartesian units) between major ticks.
- return derived().x_major_interval_;
- }
-
- Derived& x_minor_interval(double interval)
- { // aka x_minor_tick
- derived().x_minor_interval_ = interval;
- return derived();
- }
+ Derived& x_range(double min_x, double max_x)
+ {
+ if(max_x <= min_x)
+ {
+ throw std::runtime_error("Illegal Argument: X range: x_max < x_min");
+ }
+ derived().x_min = min_x;
+ derived().x_max = max_x;
+ return derived();
+ }
- Derived& x_num_minor_ticks(unsigned int num)
- {
- derived().x_num_minor_ticks_ = num;
- return derived();
- }
-
- unsigned int x_num_minor_ticks()
- { // NB NOT float or double!
- return derived().x_num_minor_ticks_;
- }
+ std::pair<double, double> x_range()
+ {
+ std::pair<double, double> r;
+ r.first = derived().x_min;
+ r.second = derived().x_max;
+ return r;
+ }
- Derived& x_range(double min_x, double max_x)
- {
- if(max_x <= min_x)
- {
- throw std::runtime_error("Illegal Argument: X range: x_max < x_min");
- }
- derived().x_min = min_x;
- derived().x_max = max_x;
- return derived();
- }
+ // Avoid clashes with class svg_1d_plot variable x_min & x_max,
+ // so use longer x_minimum, x_maximum ...
+ Derived& x_minimum(double min_x)
+ {
+ // Can't check here that x_max > x_min because may not have set x_max yet.
+ // TODO ensure that there is another check somewhere.
+ derived().x_min = min_x;
+ return derived();
+ }
- std::pair<double, double> x_range()
- {
- std::pair<double, double> r;
- r.first = derived().x_min;
- r.second = derived().x_max;
- return r;
- }
-
- // Avoid clashes with class svg_1d_plot variable x_min & x_max,
- // so use longer x_minimum, x_maximum ...
- Derived& x_minimum(double min_x)
- {
- // Can't check here that x_max > x_min because may not have set x_max yet.
- // TODO ensure that there is another check somewhere.
- derived().x_min = min_x;
- return derived();
- }
+ double x_minimum()
+ {
+ return derived().x_min;
+ }
- double x_minimum()
- {
- return derived().x_min;
- }
+ Derived& x_maximum(double x)
+ {
+ // Can't check here that x_max > x_min because may not have set x_min yet.
+ // TODO check that there is another check somewhere.
+ derived().x_max = x;
+ return derived();
+ }
- Derived& x_maximum(double x)
- {
- // Can't check here that x_max > x_min because may not have set x_min yet.
- // TODO check that there is another check somewhere.
- derived().x_max = x;
- return derived();
- }
+ double x_maximum()
+ {
+ return derived().x_max;
+ }
- double x_maximum()
- {
- return derived().x_max;
- }
+ // Stylesheet.
- // Stylesheet.
+ Derived& load_stylesheet(const std::string& file)
+ {
+ derived().image.load_stylesheet(file);
+ return derived();
+ }
- Derived& load_stylesheet(const std::string& file)
- {
- derived().image.load_stylesheet(file);
- return derived();
- }
+ // Image info (& identical const version).
- // Image info (& identical const version).
+ svg& get_svg()
+ {
+ derived()._update_image();
+ return derived().image;
+ }
- svg& get_svg()
- {
- derived()._update_image();
- return derived().image;
- }
+ const svg& get_svg() const
+ {
+ derived()._update_image();
+ return derived().image;
+ }
+ }; // template <class Derived> class axis_plot_frame
- const svg& get_svg() const
- {
- derived()._update_image();
- return derived().image;
- }
-}; // template <class Derived> class axis_plot_frame
-
-} // detail
-} // svg
-} // boost
+ } // detail
+ } // svg
+ } // boost
#endif // BOOST_SVG_AXIS_PLOT_FRAME_HPP
Modified: sandbox/SOC/2007/visualization/boost/svg_plot/svg_1d_plot.hpp
==============================================================================
--- sandbox/SOC/2007/visualization/boost/svg_plot/svg_1d_plot.hpp (original)
+++ sandbox/SOC/2007/visualization/boost/svg_plot/svg_1d_plot.hpp 2007-12-20 07:14:05 EST (Thu, 20 Dec 2007)
@@ -164,13 +164,13 @@
// TODO SVG has also a not yet implemented boldness.
double title_width_;
double legend_width_;
- double legend_x1_; // Left of legend box. (Optionally set by legend_position).
- double legend_y1_; // Top of legend box.
+ double legend_left_; // Left of legend box. (Optionally set by legend_position).
+ double legend_top_; // 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 legend_right_; // right of legend box.
+ double legend_bottom_; // bottom of legend box.
// X-Axis information.
// (Y_axis stored as one point because this is a 1D graph).
@@ -236,7 +236,7 @@
//x_units_info(0, 0, "(units)", 14, "Times New Roman", "italic", "bold", "wider", "underline", right_align, horizontal),
text_margin_(2.), // for text was 1.5 // as a fraction of the font size.
border_margin_(5), // Prevent plot window box begin right on edge.
- legend_x1_(-1), legend_x2_(-1),legend_y1_(-1),legend_y2_(-1), // Indicates not yet set.
+ legend_left_(-1), legend_right_(-1),legend_top_(-1),legend_bottom_(-1), // Indicates not yet set.
x_min(-10), x_max(10),
use_legend(false),
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-20 07:14:05 EST (Thu, 20 Dec 2007)
@@ -52,1697 +52,1704 @@
#ifndef BOOST_SVG_BOOST_PARAMETER_NAMES
#define BOOST_SVG_BOOST_PARAMETER_NAMES
- BOOST_PARAMETER_NAME(my_plot)
- BOOST_PARAMETER_NAME(container)
- BOOST_PARAMETER_NAME(title)
- BOOST_PARAMETER_NAME(stroke_color)
- BOOST_PARAMETER_NAME(fill_color)
- BOOST_PARAMETER_NAME(point_style)
- BOOST_PARAMETER_NAME(x_functor)
- BOOST_PARAMETER_NAME(size)
+ BOOST_PARAMETER_NAME(my_plot)
+ BOOST_PARAMETER_NAME(container)
+ BOOST_PARAMETER_NAME(title)
+ BOOST_PARAMETER_NAME(stroke_color)
+ BOOST_PARAMETER_NAME(fill_color)
+ BOOST_PARAMETER_NAME(point_style)
+ BOOST_PARAMETER_NAME(x_functor)
+ BOOST_PARAMETER_NAME(size)
#endif
- // TODO Why are these outside the #endif? Subset?
- // Remove when class plot used instead of Boost.Parameter.
- BOOST_PARAMETER_NAME(bezier_on)
- BOOST_PARAMETER_NAME(line_on)
- BOOST_PARAMETER_NAME(line_color)
- BOOST_PARAMETER_NAME(area_fill_color)
-
- // -----------------------------------------------------------------
- // This allows us to store plot state locally in svg_plot. We don't
- // store it in "svg" because transforming the points after they are
- // written to the document would be difficult. We store the Cartesian
- // coordinates locally and transform them before we write them.
- // -----------------------------------------------------------------
-struct svg_2d_plot_series;
-class svg_2d_plot;
+ // TODO Why are these outside the #endif? Subset?
+ // Remove when class plot used instead of Boost.Parameter.
+ BOOST_PARAMETER_NAME(bezier_on)
+ BOOST_PARAMETER_NAME(line_on)
+ BOOST_PARAMETER_NAME(line_color)
+ BOOST_PARAMETER_NAME(area_fill_color)
+
+ // -----------------------------------------------------------------
+ // This allows us to store plot state locally in svg_plot. We don't
+ // store it in "svg" because transforming the points after they are
+ // written to the document would be difficult. We store the Cartesian
+ // coordinates locally and transform them before we write them.
+ // -----------------------------------------------------------------
+ struct svg_2d_plot_series;
+ class svg_2d_plot;
-static const double wh_ = 0.7; // font text width/height ratio.
-static const double sin45 = 0.707; // Use if axis value labels are sloping.
+ static const double wh_ = 0.7; // font text width/height ratio.
+ static const double sin45 = 0.707; // Use if axis value labels are sloping.
enum y_axis_intersect {left = -1, y_intersect = 0, right = +1};
enum x_axis_intersect {bottom = -1, x_intersect = 0, top = +1};
-struct svg_2d_plot_series
-{
- // 2-D Data series points to plot.
- std::multimap<double, double> series; // Normal 'OK to plot' data values.
- std::multimap<double, double> series_limits; // 'limit' values: too big or small, or NaN.
- // multimap is used rather than vector of pairs because
- // 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;
-
- template <class T>
- svg_2d_plot_series(T begin, T end,
- std::string title, // of data series.
- const plot_point_style& point,
- const plot_line_style& line)
- :
- title(title),
- point_style(point),
- line_style(line)
- { // Constructor.
- for(T i = begin; i != end; ++i)
- { // Sort into normal and limited series.
- if(detail::pair_is_limit(*i))
- { // Either x and/or y is at limit.
- series_limits.insert(*i);
- }
- else
- { // normal point.
- series.insert(*i);
- }
- }
- } // svg_2d_plot_series
-}; // struct svg_2d_plot_series
+ struct svg_2d_plot_series
+ {
+ // 2-D Data series points to plot.
+ std::multimap<double, double> series; // Normal 'OK to plot' data values.
+ std::multimap<double, double> series_limits; // 'limit' values: too big or small, or NaN.
+ // multimap is used rather than vector of pairs because
+ // 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;
+
+ template <class T>
+ svg_2d_plot_series(T begin, T end,
+ std::string title, // of data series.
+ const plot_point_style& point,
+ const plot_line_style& line)
+ :
+ title(title),
+ point_style(point),
+ line_style(line)
+ { // Constructor.
+ for(T i = begin; i != end; ++i)
+ { // Sort into normal and limited series.
+ if(detail::pair_is_limit(*i))
+ { // Either x and/or y is at limit.
+ series_limits.insert(*i);
+ }
+ else
+ { // normal point.
+ series.insert(*i);
+ }
+ }
+ } // svg_2d_plot_series
+ }; // struct svg_2d_plot_series
-class svg_2d_plot : public detail::axis_plot_frame<svg_2d_plot>
-{ // See also svg_1d_plot.hpp for 1-D version.
-private:
- friend class detail::axis_plot_frame<svg_2d_plot>;
- // Contains functions common to 1 and 2-D.
-
- double x_scale; // Use by function transform()
- double x_shift; // to go from Cartesian to svg coordinates.
- double y_scale;
- double y_shift;
-
- // Stored so as to avoid rewriting style information constantly.
- svg image;
-
- text_style a_style; // Defaults.
-
- text_element title_info; // Plot title.
- text_element legend_header_; // legend box header or title (if any).
- text_element x_label_info; // For example: "length"
- text_element x_label_value; // For example: "1.2" or "1.2e+001"
- text_element y_label_info; // For example: "volume"
- text_element x_units_info; // For example: "mm"
- text_element y_units_info; // 2-D only.
- text_element y_label_value; // For example: "1.2" or "1.2e+001"
-
- int x_value_precision_; // precision for tick value labels, usually 3 will suffice.
- int y_value_precision_; // precision for tick value labels, usually 3 will suffice.
- // Used to decide how much space to allow for tick values.
- int x_value_ioflags_; // IO formatting flags for X-axis.
- int y_value_ioflags_; // IO formatting flags for Y-axis.
- double text_margin_; // Marginal space around text items like title,
- // as a fraction of font size, (pixels) (was fixed at 1.5).
- double border_margin_; // Marginal (pixels) space around the plot border.
- double border_width_; // plot border rectangle width.
-
- // Border information for the plot window (<= image size).
- // Allows for title and legend to be separate.
- // Initially will be set to the width and height of the graph image.
- // calculate_plot_window() sets these values.
- double plot_x1; // TODO These (and many others) also could be float?
- double plot_x2;
- double plot_y1;
- double plot_y2;
-
- // X-Axis information.
- double x_min; // minimum x value (Cartesian units).
- double x_max; // maximum x value (Cartesian units).
- double x_axis; // // x-axis (y = 0) transformed into SVG Y coordinates. -1 if not caculated yet.
- double x_major_interval_; // x_major_interval_ is the stride or interval for major x ticks.
- // (Cartesian units) set/get by x_major_interval
- double x_minor_interval_; // Interval (Cartesian units) between minor ticks.
- // No set function because x_num_minor_ticks_ used to determine this instead,
- // but one could calculate x_minor_interval_.
-
- // text width is effectively the boldness of the font.
- // But only in graphics mode rather than text mode, and style "bold"
- // and this is poor on some browsers, so recommend to not set width.
- // 0 is default, 1 is bolder, 2 very bold and a not-yet-implemented boldness.
- double image_border_width_;
- double title_font_width_;
- double legend_font_width_;
- double legend_width_; // width of legend box in pixels.
- 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.
- size_t legend_longest_; // longest string in legend box.
- double x_label_width_; // Used for value too.
- 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.
- double x_minor_tick_width_; // pixels.
- // Avoid name clash with x_m*_tick_length and width.
- unsigned int x_num_minor_ticks_; // number of minor ticks, eg 4 gives major 0, minor 1,2,3,4, major 5
- double x_major_grid_width_; // pixels.
- double x_minor_grid_width_; // pixels.
- // grid width is set in style.stroke_width
- int x_axis_position_; //
-
- // Y-Axis information.
- unsigned int y_num_minor_ticks_; // number of minor ticks, eg 4 gives major 0, minor 1,2,3,4, major 5
- double y_min; // minimum y value (Cartesian units).
- 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 X SVG coordinates. -1 if not caculated yet.
- 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.
- double y_minor_tick_width_; // pixels.
- // Avoid name clash with x_m*_tick_length and width.
- // grid width is set in style.stroke_width
- double y_major_grid_width_; // pixels.
- double y_minor_grid_width_; // pixels.
- double x_label_length_; // width (in SVG) of longest label on X-axis.
- double y_label_length_; // width (in SVG) of longest label on Y-axis.
- int y_axis_position_; //
-
- // Yes/no options.
- bool use_title; // Provide a title for the whole plot.
- bool use_legend; // Provide a legend box.
- bool use_axis; // Draw x and y axes. TODO split so can have either or both.
- bool use_plot_window_; // Use a separate plot window.
- bool use_x_label; // Label axis with text.
- bool use_y_label;
- bool use_x_major_labels; // values for major ticks.
- bool use_y_major_labels;
- bool use_x_label_units;
- bool use_y_label_units;
- int x_label_rotation_; // X_axis value labels written.
- int y_label_rotation_; // Y_axis value labels written.
- bool use_x_major_grid_;
- bool use_x_minor_grid_;
- bool use_y_major_grid_;
- bool use_y_minor_grid_;
-
- // Note: can have ticks both up and/or down, and/or left and right.
- bool use_up_ticks;
- bool use_down_ticks;
- bool use_x_ticks; // = use_up_ticks || use_down_ticks
- bool use_left_ticks;
- bool use_right_ticks;
- // bool use_y_ticks; // = use_left_ticks || use_right_ticks
- // was external style.
- bool use_x_ticks_on_plot_window_; // Value labels & ticks on the plot window rather than on X-axis.
- bool use_y_ticks_on_plot_window_; // Value labels & ticks on the plot window rather than on Y-axis.
- bool use_x_axis_lines_; // Draw a horizontal X-axis line.
- 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_;
- unsigned int longest_; // string in legend box.
-
- // Where we will be storing the data points (series) for transformation.
- std::vector<svg_2d_plot_series> series; // Defined above.
-
- std::string plot_window_clip; // = "clip_plot_window" id for clippath
-
- // http://www.w3.org/TR/SVG/masking.html#ClipPathElement 14.1 Introduction
- // clipping paths, which uses any combination of 'path', 'text' and basic shapes
- // to serve as the outline where everything on the "inside" of the outline
- // is allowed to show through but everything on the outside is masked out.
- // So the plot_window_clip limits display to a plot_window rectangle.
-
- //text_style label_style(40); // Or use all defaults.
- //text_style(int size = 12, // defaults:
- //const std::string& font = "sans",
- //const std::string& style = "",
- //const std::string& weight = "",
- //const std::string& stretch = "",
- //const std::string& decoration = "")
- //label_style().font_weight("bold");
-
-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.
-
-
- a_style(16, "serif"),
- 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", "italic", "", "bold", "", center_align, horizontal),
- legend_font_width_(0.5),
- x_label_info(0, 0, "X Axis", 14, "Verdana", "", "bold", "", "", center_align, horizontal),
- x_units_info(0, 0, "(units)", 14, "Verdana", "", "", "", "", center_align, horizontal, a_style),
- x_label_value(0, 0, "", 12, "Verdana", "", "", "", "", center_align, horizontal),
- // TODO use this and provide way to set'n'get separately.
- x_axis(-1), // -1 means not yet valid.
- y_axis(-1), // -1 means not yet valid.
- x_label_width_(2),
- x_axis_width_(2), // Width of X-axis line.
- 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_(5),
- y_axis_width_(2), // vertical line.
- x_label_rotation_(horizontal),
- y_label_rotation_(horizontal),
- // 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 any defaults, so std::dec is wise.
- image_border_width_(1),
- text_margin_(2.), // for axis label text, as a multiplier of the font size.
- border_margin_(10), // Prevent plot window box beginning 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_(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.),
- x_major_tick_width_(2.),
- x_minor_tick_width_(1.),
- y_major_tick_length_(10.), // If both left and right, total is twice this.
- y_minor_tick_length_(5.),
- y_major_tick_width_(2.),
- y_minor_tick_width_(1.),
- // grids
- x_major_grid_width_(1.),
- 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_
- y_minor_interval_(0), // but given a value here for safety.
- x_axis_position_(0),
- y_axis_position_(0),
- x_label_length_(0),
- y_label_length_(0),
-
- 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
- use_left_ticks(true), // On y-axis.
- use_right_ticks(false), // On y-axis
- //use_y_ticks(true), // = use_left_ticks || use_right_ticks TODO get rid of this. NOT useful
- use_x_ticks_on_plot_window_(false), // was external_style
- use_y_ticks_on_plot_window_(false), // was external_style
- use_x_label_units(false),
- use_y_label_units(false),
- use_x_major_labels(true), // tick value labels.
- use_y_major_labels(true),
- use_x_label(true), // "X-axis"
- use_y_label(true), // "Y-axis" - true for 2-D, false for 1-D.
- use_title(true),
- use_legend(false), use_axis(true),
- use_x_axis_lines_(true), // draw horizontal X-axis line.
- use_y_axis_lines_(true), // draw vertical Y-axis line.
- use_x_major_grid_(true),
- use_x_minor_grid_(false),
- use_y_major_grid_(true),
- use_y_minor_grid_(false),
- use_plot_window_(true),
- use_line(true)
- // TODO but needs Boost-Parameter removed to do properly.
-
- {
- image_size(500, 400); // Default image size for 2-D.
- // 2-D usually needs to be squarer than 1-D.
+
+ class svg_2d_plot : public detail::axis_plot_frame<svg_2d_plot>
+ { // See also svg_1d_plot.hpp for 1-D version.
+
+ private:
+ friend class detail::axis_plot_frame<svg_2d_plot>;
+ // Contains functions common to 1 and 2-D.
+
+ double x_scale; // Use by function transform()
+ double x_shift; // to go from Cartesian to svg coordinates.
+ double y_scale;
+ double y_shift;
+
+ // Stored so as to avoid rewriting style information constantly.
+ svg image;
+
+ text_style a_style; // Defaults.
+
+ text_element title_info; // Plot title.
+ text_element legend_header_; // legend box header or title (if any).
+ text_element x_label_info; // For example: "length"
+ text_element x_label_value; // For example: "1.2" or "1.2e+001"
+ text_element y_label_info; // For example: "volume"
+ text_element x_units_info; // For example: "mm"
+ text_element y_units_info; // 2-D only.
+ text_element y_label_value; // For example: "1.2" or "1.2e+001"
+
+ int x_value_precision_; // precision for tick value labels, usually 3 will suffice.
+ int y_value_precision_; // precision for tick value labels, usually 3 will suffice.
+ // Used to decide how much space to allow for tick values.
+ int x_value_ioflags_; // IO formatting flags for X-axis.
+ int y_value_ioflags_; // IO formatting flags for Y-axis.
+ double text_margin_; // Marginal space around text items like title,
+ // as a fraction of font size, (pixels) (was fixed at 1.5).
+ double border_margin_; // Marginal (pixels) space around the plot border.
+ double border_width_; // plot border rectangle width.
+
+ // Border information for the plot window (<= image size).
+ // Allows for title and legend to be separate.
+ // Initially will be set to the width and height of the graph image.
+ // calculate_plot_window() sets these values.
+ double plot_x1; // TODO These (and many others) also could be float?
+ double plot_x2;
+ double plot_y1;
+ double plot_y2;
+
+ // X-Axis information.
+ double x_min; // minimum x value (Cartesian units).
+ double x_max; // maximum x value (Cartesian units).
+ double x_axis; // // x-axis (y = 0) transformed into SVG Y coordinates. -1 if not caculated yet.
+ double x_major_interval_; // x_major_interval_ is the stride or interval for major x ticks.
+ // (Cartesian units) set/get by x_major_interval
+ double x_minor_interval_; // Interval (Cartesian units) between minor ticks.
+ // No set function because x_num_minor_ticks_ used to determine this instead,
+ // but one could calculate x_minor_interval_.
+
+ // text width is effectively the boldness of the font.
+ // But only in graphics mode rather than text mode, and style "bold"
+ // and this is poor on some browsers, so recommend to not set width.
+ // 0 is default, 1 is bolder, 2 very bold and a not-yet-implemented boldness.
+ double image_border_width_;
+ double title_font_width_;
+ double legend_font_width_;
+ legend_places legend_place_;
+ double legend_width_; // width of legend box in pixels.
+ double legend_height_; // height of legend box in pixels.
+ double legend_left_; // Left of legend box. (Optionally set by legend_top_left).
+ double legend_top_; // 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_right_; // right of legend box.
+ double legend_bottom_; // bottom of legend box.
+ size_t legend_longest_; // longest string in legend box.
+ double x_label_width_; // Used for value too.
+ 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.
+ double x_minor_tick_width_; // pixels.
+ // Avoid name clash with x_m*_tick_length and width.
+ unsigned int x_num_minor_ticks_; // number of minor ticks, eg 4 gives major 0, minor 1,2,3,4, major 5
+ double x_major_grid_width_; // pixels.
+ double x_minor_grid_width_; // pixels.
+ // grid width is set in style.stroke_width
+ int x_axis_position_; //
+
+ // Y-Axis information.
+ unsigned int y_num_minor_ticks_; // number of minor ticks, eg 4 gives major 0, minor 1,2,3,4, major 5
+ double y_min; // minimum y value (Cartesian units).
+ 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 X SVG coordinates. -1 if not caculated yet.
+ 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.
+ double y_minor_tick_width_; // pixels.
+ // Avoid name clash with x_m*_tick_length and width.
+ // grid width is set in style.stroke_width
+ double y_major_grid_width_; // pixels.
+ double y_minor_grid_width_; // pixels.
+ double x_label_length_; // width (in SVG) of longest label on X-axis.
+ double y_label_length_; // width (in SVG) of longest label on Y-axis.
+ int y_axis_position_; //
+
+ // Yes/no options.
+ bool use_title; // Provide a title for the whole plot.
+ bool use_legend; // Provide a legend box.
+ bool use_outside_legend_;
+ bool use_axis; // Draw x and y axes. TODO split so can have either or both.
+ bool use_plot_window_; // Use a separate plot window.
+ bool use_x_label; // Label axis with text.
+ bool use_y_label;
+ bool use_x_major_labels; // values for major ticks.
+ bool use_y_major_labels;
+ bool use_x_label_units;
+ bool use_y_label_units;
+ int x_label_rotation_; // X_axis value labels written.
+ int y_label_rotation_; // Y_axis value labels written.
+ bool use_x_major_grid_;
+ bool use_x_minor_grid_;
+ bool use_y_major_grid_;
+ bool use_y_minor_grid_;
+
+ // Note: can have ticks both up and/or down, and/or left and right.
+ bool use_up_ticks;
+ bool use_down_ticks;
+ bool use_x_ticks; // = use_up_ticks || use_down_ticks
+ bool use_left_ticks;
+ bool use_right_ticks;
+ // bool use_y_ticks; // = use_left_ticks || use_right_ticks
+ // was external style.
+ bool use_x_ticks_on_plot_window_; // Value labels & ticks on the plot window rather than on X-axis.
+ bool use_y_ticks_on_plot_window_; // Value labels & ticks on the plot window rather than on Y-axis.
+ bool use_x_axis_lines_; // Draw a horizontal X-axis line.
+ 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_;
+ unsigned int longest_; // string in legend box.
+
+ // Where we will be storing the data points (series) for transformation.
+ std::vector<svg_2d_plot_series> series; // Defined above.
+
+ std::string plot_window_clip; // = "clip_plot_window" id for clippath
+
+ // http://www.w3.org/TR/SVG/masking.html#ClipPathElement 14.1 Introduction
+ // clipping paths, which uses any combination of 'path', 'text' and basic shapes
+ // to serve as the outline where everything on the "inside" of the outline
+ // is allowed to show through but everything on the outside is masked out.
+ // So the plot_window_clip limits display to a plot_window rectangle.
+
+ //text_style label_style(40); // Or use all defaults.
+ //text_style(int size = 12, // defaults:
+ //const std::string& font = "sans",
+ //const std::string& style = "",
+ //const std::string& weight = "",
+ //const std::string& stretch = "",
+ //const std::string& decoration = "")
+ //label_style().font_weight("bold");
+
+ 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.
+
+ a_style(16, "serif"),
+ 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", "italic", "", "bold", "", center_align, horizontal),
+ legend_font_width_(0.5),
+ x_label_info(0, 0, "X Axis", 14, "Verdana", "", "bold", "", "", center_align, horizontal),
+ x_units_info(0, 0, "(units)", 14, "Verdana", "", "", "", "", center_align, horizontal, a_style),
+ x_label_value(0, 0, "", 12, "Verdana", "", "", "", "", center_align, horizontal),
+ // TODO use this and provide way to set'n'get separately.
+ x_axis(-1), // -1 means not yet valid.
+ y_axis(-1), // -1 means not yet valid.
+ x_label_width_(2),
+ x_axis_width_(2), // Width of X-axis line.
+ 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_(5),
+ y_axis_width_(2), // vertical line.
+ x_label_rotation_(horizontal),
+ y_label_rotation_(horizontal),
+ // 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 any defaults, so std::dec is wise.
+ image_border_width_(1),
+ text_margin_(2.), // for axis label text, as a multiplier of the font size.
+ border_margin_(10), // Prevent plot window box beginning 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_left_(-1), legend_right_(-1),legend_top_(-1),legend_bottom_(-1), // Default top left of plot window.
+ legend_place_(inside), // default but interacts with using plot_window
+ 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_(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.),
+ x_major_tick_width_(2.),
+ x_minor_tick_width_(1.),
+ y_major_tick_length_(10.), // If both left and right, total is twice this.
+ y_minor_tick_length_(5.),
+ y_major_tick_width_(2.),
+ y_minor_tick_width_(1.),
+ // grids
+ x_major_grid_width_(1.),
+ 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_
+ y_minor_interval_(0), // but given a value here for safety.
+ x_axis_position_(0),
+ y_axis_position_(0),
+ x_label_length_(0),
+ y_label_length_(0),
+
+ 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
+ use_left_ticks(true), // On y-axis.
+ use_right_ticks(false), // On y-axis
+ //use_y_ticks(true), // = use_left_ticks || use_right_ticks TODO get rid of this. NOT useful
+ use_x_ticks_on_plot_window_(false), // was external_style
+ use_y_ticks_on_plot_window_(false), // was external_style
+ use_x_label_units(false),
+ use_y_label_units(false),
+ use_x_major_labels(true), // tick value labels.
+ use_y_major_labels(true),
+ use_x_label(true), // "X-axis"
+ use_y_label(true), // "Y-axis" - true for 2-D, false for 1-D.
+ use_title(true),
+ use_legend(false),
+ use_outside_legend_(true),
+ use_axis(true),
+ use_x_axis_lines_(true), // draw horizontal X-axis line.
+ use_y_axis_lines_(true), // draw vertical Y-axis line.
+ use_x_major_grid_(true),
+ use_x_minor_grid_(false),
+ use_y_major_grid_(true),
+ use_y_minor_grid_(false),
+ use_plot_window_(false),
+ use_line(true)
+ // TODO but needs Boost-Parameter removed to do properly.
- using namespace boost::svg::detail; // avoid detail::
+ {
+ image_size(500, 400); // Default image size for 2-D.
+ // 2-D usually needs to be squarer than 1-D.
- // Build the document tree by adding all children of the root node.
- for(int i = 0; i < SVG_PLOT_DOC_CHILDREN; ++i)
- {
- image.add_g_element();
- }
- set_ids();
+ using namespace boost::svg::detail; // avoid detail::
- // Set other SVG color, stroke & width defaults for various child PLOT nodes.
+ // Build the document tree by adding all children of the root node.
+ for(int i = 0; i < SVG_PLOT_DOC_CHILDREN; ++i)
+ {
+ image.add_g_element();
+ }
+ set_ids();
- // 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(yellow); // TODO test only ?
- image.get_g_element(PLOT_BACKGROUND).style().stroke_width(image_border_width_); //
- image.get_g_element(PLOT_WINDOW_BACKGROUND).style().fill_color(white);
- image.get_g_element(PLOT_WINDOW_BACKGROUND).style().stroke_width(1).stroke_color(yellow);
- 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_axis_width_);
- image.get_g_element(PLOT_Y_AXIS).style().stroke_color(black).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(black);
- 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.
+ // Set other SVG color, stroke & width defaults for various child PLOT nodes.
- // Note that widths are stored in member data *and* copied here.
- // Not sure if this is wise but ...
+ // 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(yellow); // TODO test only ?
+ image.get_g_element(PLOT_BACKGROUND).style().stroke_width(image_border_width_); //
+ image.get_g_element(PLOT_WINDOW_BACKGROUND).style().fill_color(white);
+ image.get_g_element(PLOT_WINDOW_BACKGROUND).style().stroke_width(1).stroke_color(yellow);
+ 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_axis_width_);
+ image.get_g_element(PLOT_Y_AXIS).style().stroke_color(black).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(black);
+ 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.
- // Ticks
- 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);
- image.get_g_element(PLOT_X_MINOR_TICKS).style().stroke_width(x_minor_tick_width_).stroke_color(black);
- }
- if(use_left_ticks || use_right_ticks)
- {
- image.get_g_element(PLOT_Y_MAJOR_TICKS).style().stroke_width(y_major_tick_width_).stroke_color(black);
- image.get_g_element(PLOT_Y_MINOR_TICKS).style().stroke_width(y_minor_tick_width_).stroke_color(black);
- }
- // Grids.
- // Default color & width for grid, used or not.
- image.get_g_element(PLOT_X_MAJOR_GRID).style().stroke_width(x_major_grid_width_).stroke_color(svg_color(200, 220, 255));
- BOOST_ASSERT(image.get_g_element(PLOT_X_MAJOR_GRID).style().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() // TODO is this only used once in constructor and should be inline?
- { // document ids for use in <g id = "PLOT_TITLE".../>
- for(int i = 0; i < detail::SVG_PLOT_DOC_CHILDREN; ++i)
- {
- image.get_g_element(i).id(detail::document_ids[i]);
- }
- } // void set_ids()
+ // Note that widths are stored in member data *and* copied here.
+ // Not sure if this is wise but ...
- //void calculate_transform() now inline in calcualte_plot_window
- //{ // Calculate scale and shift factors for transform from Cartesian to plot.
- // // SVG image is 0, 0 at top left, Cartesian at bottom left.
- // x_scale = (plot_x2 - plot_x1) / (x_max - x_min);
- // x_shift = plot_x1 - x_min *(plot_x2 - plot_x1) / (x_max - x_min);
- // y_scale = -(plot_y2-plot_y1) / (y_max-y_min);
- // y_shift = plot_y1 - (y_max * (plot_y1 - plot_y2) / (y_max - y_min));
- //} // void calculate_transform()
-
- void transform_pair(std::pair<double, double>& pt)
- { // Transform both x and y from Cartesian to SVG coordinates.
- // SVG image is 0, 0 at top left, Cartesian at bottom left.
- transform_point(pt.first, pt.second);
- }
-
- void calculate_plot_window()
- { // The plot window is used to set a clip path:
- // this ensures that data points and lines (and anything else)
- // outside this window are NOT drawn.
- // Start by assuming we can use all the svg image,
- // but reduce by width of any image border.
- plot_x1 = 0 + image_border_width_; // left
- plot_y1 = 0 + image_border_width_; // top
- plot_x2 = image.x_size() - image_border_width_; // right
- plot_y2 = image.y_size() - image_border_width_; // bottom
-
- calculate_legend_box();
- 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.
- }
- if(use_x_label)
- { // Leave space at bottom for X axis label.
- plot_y2 -= x_label_info.font_size() * (text_margin_);
- }
- if(use_y_label)
- { // Leave space at left for Y axis label.
- plot_x1 += y_label_info.font_size() * (text_margin_ - 0.5);
- }
- 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_ + 0.5);
- }
- 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 plot window border rectangle to show OK.
- // border_margin is to prevent it being right on the 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();
- }
- // Check if the axes will intersect.
- y_axis_position_ = y_intersect; // Y-axis will intersect X-axis.
- if (x_min > std::numeric_limits<double>::min())
- { // Y-axis > 0 so will not intersect X -axis, (all positive)
- y_axis_position_ = left; // Y-axis free to left of end of X-axis.
- use_y_ticks_on_plot_window_ = true;
- }
- else if (y_max < -std::numeric_limits<double>::min())
- { // Y-axis < 0 so will not intersect X -axis, (all negative)
- y_axis_position_ = right;
- use_y_ticks_on_plot_window_ = true;
- }
- x_axis_position_ = x_intersect; // X-axis will intersect Y-axis.
- if (y_min > std::numeric_limits<double>::min()) // all definitely > zero.
- { // y_min > 0 so X-axis will not intersect Y-axis, so use bottom plot window.
- x_axis_position_ = bottom; // X-axis to bottom.
- use_x_ticks_on_plot_window_ = true;
- }
- else if(y_max < -std::numeric_limits<double>::min()) // all definitely < zero.
- { // // y_max < 0 so X-axis will not intersect Y-axis, so use top plot window.
- x_axis_position_ = top; // X-axis to top.
- use_x_ticks_on_plot_window_ = true;
- }
+ // Ticks
+ 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);
+ image.get_g_element(PLOT_X_MINOR_TICKS).style().stroke_width(x_minor_tick_width_).stroke_color(black);
+ }
+ if(use_left_ticks || use_right_ticks)
+ {
+ image.get_g_element(PLOT_Y_MAJOR_TICKS).style().stroke_width(y_major_tick_width_).stroke_color(black);
+ image.get_g_element(PLOT_Y_MINOR_TICKS).style().stroke_width(y_minor_tick_width_).stroke_color(black);
+ }
+ // Grids.
+ // Default color & width for grid, used or not.
+ image.get_g_element(PLOT_X_MAJOR_GRID).style().stroke_width(x_major_grid_width_).stroke_color(svg_color(200, 220, 255));
+ BOOST_ASSERT(image.get_g_element(PLOT_X_MAJOR_GRID).style().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);
+
+ legend_place_ = (use_plot_window_) ? outside_right : inside; // Defaults.
+ // Note if set plot_window_on() then also need to set legend_place.
+ // (if set a default in plot_window then call to set legend place must to come *after* it.
+ // So not set a default? But leaving it as inside is worse?)
+
+ } // svg_2d_plot() default constructor.
+
+ private:
+ // svg_2d_plot Member Functions.
+
+ void set_ids() // TODO is this only used once in constructor and should be inline?
+ { // document ids for use in <g id = "PLOT_TITLE".../>
+ for(int i = 0; i < detail::SVG_PLOT_DOC_CHILDREN; ++i)
+ {
+ image.get_g_element(i).id(detail::document_ids[i]);
+ }
+ } // void set_ids()
- // 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 average width height ratio wh is used:
-
- // We would really like to know the length of the longest value label here!
- // Might convert the max and then use its .length()?
- int chars = (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).
- chars += 5; // Also need space for e, sign & 3 exponent digits = 5)
- }
- else if((y_value_ioflags_ & std::ios::fixed) == std::ios::fixed)
- { // precision is
- chars += 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?
- }
- y_label_length_ = 0; // SVG units.
- if (y_label_rotation_ == horizontal)
- { // Move edge right to give space for y_value_precision_ digits.
- y_label_length_ += y_label_value.font_size() * (chars * wh_);
- }
- else if((y_label_rotation_ == upward) || (y_label_rotation_ == downward))
- { // Only need one char width from Y-axis label.
- y_label_length_ += y_label_value.font_size() * 1.5;
- }
- else
- { // Assume some slope 45, so diagonally down from tick,
- // and takes a bit less room.
- y_label_length_ = y_label_value.font_size() * chars * wh_ * sin45;
- }
- if (use_y_major_labels && (y_axis_position_ != right) )
- {
- //if (abs(x_min/(x_max - x_min)) < 0.05) // < 5% of range.
- // // Y-axis is too close to the axis label.
- // // Want to do this:
- // //((y_axis - plot_x1) < (y_label_length_ - y_major_tick_width_)) )
- // // needs to calculate transform to get into SVG units, but this is changing plot_x1 !!
- //{ // force onto plot window. BUT this only looks right if plot window is on.
- // // because makr ticks and label are on the plot window
- // use_y_ticks_on_plot_window_ = true;
- //}
- //if (use_y_ticks_on_plot_window_) // on plot window
- { // Move plot window right to make space for value labels,
- plot_x1 += y_label_length_;
- }
- }
+ //void calculate_transform() now inline in calcualte_plot_window
+ //{ // Calculate scale and shift factors for transform from Cartesian to plot.
+ // // SVG image is 0, 0 at top left, Cartesian at bottom left.
+ // x_scale = (plot_x2 - plot_x1) / (x_max - x_min);
+ // x_shift = plot_x1 - x_min *(plot_x2 - plot_x1) / (x_max - x_min);
+ // y_scale = -(plot_y2-plot_y1) / (y_max-y_min);
+ // y_shift = plot_y1 - (y_max * (plot_y1 - plot_y2) / (y_max - y_min));
+ //} // void calculate_transform()
+
+ void transform_pair(std::pair<double, double>& pt)
+ { // Transform both x and y from Cartesian to SVG coordinates.
+ // SVG image is 0, 0 at top left, Cartesian at bottom left.
+ transform_point(pt.first, pt.second);
+ }
+ void calculate_plot_window()
+ { // The plot window is used to set a clip path:
+ // this ensures that data points and lines (and anything else)
+ // outside this window are NOT drawn.
+ // Start by assuming we can use all the svg image,
+ // but reduce by width of any image border.
+ plot_x1 = 0 + image_border_width_; // left
+ plot_y1 = 0 + image_border_width_; // top
+ plot_x2 = image.x_size() - image_border_width_; // right
+ plot_y2 = image.y_size() - image_border_width_; // bottom
+
+ 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_ + 0.5);
+ }
+
+ size_legend_box();
+ place_legend_box();
+ if(use_x_label)
+ { // Leave space at bottom for X axis label.
+ plot_y2 -= x_label_info.font_size() * (text_margin_);
+ }
+ if(use_y_label)
+ { // Leave space at left for Y axis label.
+ plot_x1 += y_label_info.font_size() * (text_margin_ - 0.5);
+ }
+ 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 plot window border rectangle to show OK.
+ // border_margin is to prevent it being right on the 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();
+ }
+ // Check if the axes will intersect.
+ y_axis_position_ = y_intersect; // Y-axis will intersect X-axis.
+ if (x_min > std::numeric_limits<double>::min())
+ { // Y-axis > 0 so will not intersect X -axis, (all positive)
+ y_axis_position_ = left; // Y-axis free to left of end of X-axis.
+ use_y_ticks_on_plot_window_ = true;
+ }
+ else if (y_max < -std::numeric_limits<double>::min())
+ { // Y-axis < 0 so will not intersect X -axis, (all negative)
+ y_axis_position_ = right;
+ use_y_ticks_on_plot_window_ = true;
+ }
+ x_axis_position_ = x_intersect; // X-axis will intersect Y-axis.
+ if (y_min > std::numeric_limits<double>::min()) // all definitely > zero.
+ { // y_min > 0 so X-axis will not intersect Y-axis, so use bottom plot window.
+ x_axis_position_ = bottom; // X-axis to bottom.
+ use_x_ticks_on_plot_window_ = true;
+ }
+ else if(y_max < -std::numeric_limits<double>::min()) // all definitely < zero.
+ { // // y_max < 0 so X-axis will not intersect Y-axis, so use top plot window.
+ x_axis_position_ = top; // X-axis to top.
+ use_x_ticks_on_plot_window_ = true;
+ }
+
+ // 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 average width height ratio wh is used:
+
+ // We would really like to know the length of the longest value label here!
+ // Might convert the max and then use its .length()?
+ int chars = (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).
+ chars += 5; // Also need space for e, sign & 3 exponent digits = 5)
+ }
+ else if((y_value_ioflags_ & std::ios::fixed) == std::ios::fixed)
+ { // precision is
+ chars += 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?
+ }
+ y_label_length_ = 0; // SVG units.
+ if (y_label_rotation_ == horizontal)
+ { // Move edge right to give space for y_value_precision_ digits.
+ y_label_length_ += y_label_value.font_size() * (chars * wh_);
+ }
+ else if((y_label_rotation_ == upward) || (y_label_rotation_ == downward))
+ { // Only need one char width from Y-axis label.
+ y_label_length_ += y_label_value.font_size() * 1.5;
+ }
+ else
+ { // Assume some slope 45, so diagonally down from tick,
+ // and takes a bit less room.
+ y_label_length_ = y_label_value.font_size() * chars * wh_ * sin45;
+ }
+ if (use_y_major_labels && (y_axis_position_ != right) )
+ {
+ //if (abs(x_min/(x_max - x_min)) < 0.05) // < 5% of range.
+ // // Y-axis is too close to the axis label.
+ // // Want to do this:
+ // //((y_axis - plot_x1) < (y_label_length_ - y_major_tick_width_)) )
+ // // needs to calculate transform to get into SVG units, but this is changing plot_x1 !!
+ //{ // force onto plot window. BUT this only looks right if plot window is on.
+ // // because makr ticks and label are on the plot window
+ // use_y_ticks_on_plot_window_ = true;
+ //}
+ //if (use_y_ticks_on_plot_window_) // on plot window
+ { // Move plot window right to make space for value labels,
+ plot_x1 += y_label_length_;
+ }
+ }
+
+ if (use_x_major_labels && (use_x_ticks_on_plot_window_ || (x_axis_position_ != top) ))
+ { // 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_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, so * sin(45) = 0.707.
+ l *= sin45;
+ }
+ }
+ plot_y2 -= x_label_value.font_size() * l * wh_; // Move up.
+ }
+ if(use_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!
+ }
+ if(use_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_);
+ }
+
+
+ if (use_x_axis_lines_)
+ { // Want a X-axis line, so check if range include zero, so axes intersect,
+ // and x_axis is svg coordinate of Y-axis (usually y = 0).
+ // If not fix axis to bottom of the plot window
+ // and leave space (and quiggle between) to show this.
+ if (x_axis_position_ == bottom) // All definitely > zero.
+ { // y_min > 0 so X-axis will not intersect Y-axis, so use plot window.
+ x_axis = plot_y2; // X-axis to bottom,
+ //plot_y2 -= 2 * y_label_info.font_size(); // with a space.
+ }
+ else if(x_axis_position_ == top) // definitely < zero.
+ { // // y_max < 0 so X-axis will not intersect Y-axis, so use plot window.
+ x_axis = plot_y1; // X-axis to top,
+ //plot_y1 += 2 * y_label_info.font_size(); // with a space.
+ }
+ else
+ { // y_axis_position_ == y_intersect
+ // Calculate below after transform is calculated.
+ }
+ } // if (use_x_axis_)
+
+ if (use_y_axis_lines_)
+ { // Want a Y-axis line, so check if range include zero, so axes intersect,
+ // and y_axis is svg coordinate of X-axis (usually x = 0).
+ // If not fix axis to left of the plot window
+ // and leave space (and quiggle between) to show this.
+ if (y_axis_position_ == left) // all definitely > zero.
+ { // Y-axis will not intersect X -axis, so put Y-axis line to left of plot window.
+ y_axis = plot_x1; // Y-axis to left,
+ //plot_x1 += 2 * y_label_info.font_size(); // with a space.
+ }
+ else if(y_axis_position_ == right)
+ {
+ y_axis = plot_x2; // Y-axis to right of plot window,
+ //plot_x2 -= 2 * y_label_info.font_size(); // with a space.
+ }
+ else
+ { // x_axis_position_ == x_intersect
+ // Calculate below after transform is calculated.
+ }
+ } // if (use_y_axis_)
+
+
+ // Calculate scale and shift factors for transform from Cartesian to plot.
+ // SVG image is 0, 0 at top left,y increase *downwards*
+ // Cartesian 0, 0 at bottom left, y increasing upwards.
+ x_scale = (plot_x2 - plot_x1) / (x_max - x_min);
+ x_shift = plot_x1 - x_min *(plot_x2 - plot_x1) / (x_max - x_min);
+ y_scale = -(plot_y2-plot_y1) / (y_max-y_min);
+ y_shift = plot_y1 - (y_max * (plot_y1 - plot_y2) / (y_max - y_min));
+
+ if (use_x_axis_lines_)
+ {
+ if(x_axis_position_ == x_intersect)
+ { // Y Range *does* include zero, so x_axis not yet calculated.
+ double y(0.); // Use y = 0
+ transform_y(y);
+ x_axis = y; // svg Y coordinate of horizontal X-axis line.
+ }
+ }
+ if (use_y_axis_lines_)
+ { // May need to calculate axes, if will intersect.
+ if(y_axis_position_ == y_intersect)
+ { // X Range *does* include zero, so y_axis not yet calculated.
+ double x(0.);
+ transform_x(x);
+ y_axis = x; // SVG x coordinate of vertical Y-axis.
+ }
+ }
+ if (use_plot_window_)
+ { // Draw plot window rectangle with background and/or border.
+ image.get_g_element(detail::PLOT_WINDOW_BACKGROUND).push_back(
+ new rect_element(plot_x1, plot_y1, (plot_x2 - plot_x1), plot_y2 - plot_y1));
+ }
+
+ } // calculate_plot_window
+
+ void draw_y_axis()
+ {
+ double x;
+ x = y_axis; // Y-axis (x = 0) transformed into X SVG coordinates.
+ // Perhaps shifted to left or right if origin is missing.
+
+ if(use_y_axis_lines_)
+ { // Draw the vertical Y-axis line (at cartesian x = 0).
+ double ybottom = plot_y2;
+ if (use_down_ticks && use_y_ticks_on_plot_window_ && (x_axis_position_ == x_intersect) )
+ { // 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(x, plot_y1, x, 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.
+ path_element& minor_tick_path = image.get_g_element(detail::PLOT_Y_MINOR_TICKS).path();
+ path_element& major_tick_path = image.get_g_element(detail::PLOT_Y_MAJOR_TICKS).path();
+ path_element& minor_grid_path = image.get_g_element(detail::PLOT_Y_MINOR_GRID).path();
+ path_element& major_grid_path = image.get_g_element(detail::PLOT_Y_MAJOR_GRID).path();
+
+ if(use_y_ticks_on_plot_window_)
+ { // TODO ensure that labels allow space. - they don't at present.
+ // Was y_external style - so both labels and ticks are OUTSIDE the plot window.
+ //
+ }
+
+ // y_minor_jump is the interval between minor ticks.
+ double y_minor_jump = y_major_interval_ / ((double)(y_num_minor_ticks_ + 1.) );
+ // TODO Problem here with 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 ls or few bits out? Seems to fail for y = 100, for example.
+
+ // Draw the ticks on the positive side.
+ for(double y = 0; y <= y_max; y += y_major_interval_)
+ {
+ 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.
+ // These are just ignored in draw_x_minor_ticks.
+ // 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.
+ 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 the ticks on the negative side.
+ for(double y = 0; y >= y_min; y -= y_major_interval_)
+ {
+ for(double j=y; j > y-y_major_interval_; j-= y_major_interval_ / (y_num_minor_ticks_ + 1))
+ { // Draw minor ticks.
+ 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_axis
+
+ void draw_y_label()
+ {
+ // image.get_g_element(detail::PLOT_Y_LABEL).style().stroke_color(black);
+ // Now set in constructor, and can be changed with member function .
+
+ std::string label = y_label_info.text(); // x_axis label, and optional units.
+ if (use_x_label_units && (y_units_info.text() != ""))
+ { // Append the units, if any, providing brackets ().
+ // TODO Is this the best policy - or should the user provide the ()s????
+ label += " (" + y_units_info.text() + ")";
+ }
- if (use_x_major_labels && (use_x_ticks_on_plot_window_ || (x_axis_position_ != top) ))
- { // 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_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;
+ image.get_g_element(detail::PLOT_Y_LABEL).push_back(new
+ text_element(y_label_info.font_size() * 1.5,
+ // shift over one char height to right from left edge of image.
+ (plot_y2 + plot_y1) / 2., // center on the plot window.
+ label, // "Y-Axis" for example.
+ y_label_info.font_size(),
+ y_label_info.font_family(),
+ "", "", "", "",
+ center_align, // One might want it to left or right_align?
+ upward)); // Y label must be drawn vertically.
+ } // draw_y_label
+
+ void draw_y_major_ticks(double value, path_element& tick_path, path_element& grid_path)
+ { // Draw Y axis major ticks, tick value labels & grids.
+ double y1(value);
+ transform_y(y1); // cartesian to SVG coordinates.
+ double x1(0.); // left end of tick.
+ double x2(image.y_size()); // right end of tick.
+ if(use_y_major_grid_)
+ { // Draw horizontal major grid line.
+ if(!use_plot_window_)
+ { // TODO is this right?
+ //if (use_title())
+ //{ // title has no effect if at the top.
+ // y1 += title_info.font_size() * text_margin_;
+ //}
+ if(use_y_label)
+ { // Start further right to give space for y axis value label.
+ y1 -= y_label_value.font_size() * text_margin_ ;
+ }
+
+ if(use_left_ticks)
+ { // And similarly for left ticks.
+ y1 -= y_major_tick_length_;
+ }
+ }
+ else
+ { // Do use_plot_window.
+ x1 = plot_x1 + 1;
+ x2 = plot_x2 - 1;
+ }
+ 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_;
+ if(use_y_ticks_on_plot_window_) // (was external_style)
+ { // Start ticks on the plot window border.
+ x1 = plot_x1; // x1 = left,
+ x2 = plot_x1; // x2 = right.
+ }
+ else
+ { // Internal style ticks on vertical Y-axis.
+ x1 = y_axis; // Y-axis line.
+ x2 = y_axis;
+ }
+ if(use_left_ticks)
+ {
+ x1 -= y_tick_length; // left
+ }
+ if (use_right_ticks)
+ {
+ x2 += y_tick_length; // right.
+ }
+ tick_path.M(x1, y1).L(x2, y1); // Draw the major tick.
+ // leaving x1 at the left most end of any tick.
}
- if ((x_label_rotation_ == upward) || (x_label_rotation_ == downward))
- { // Need space for longest.
+
+ if(use_y_major_labels)
+ { // Label the tick with value, for example "1.2"
+ std::stringstream label;
+ label.precision(y_value_precision_);
+ label.flags(y_value_ioflags_); // set ALL IOflags.
+ label << value; // Example: label.str() == "20" or "0.25" or "1.2e+015"
+ if(use_left_ticks)
+ {
+ if (y_minor_tick_length_ > y_minor_tick_length_)
+ { // In case some joker has made the minor ticks longer than the major,
+ // we might need to move left more for the longer tick.
+ x1 -= (y_minor_tick_length_ - y_minor_tick_length_);
+ }
+ x1 -= y_label_value.font_size(); // move left by a font width.
+ }
+ else
+ { // No need to move if right tick, or none.
+ }
+ // Need to work out how much space value labels will need.
+ double y = y1;
+ align_style alignment = center_align;
+ if(use_y_ticks_on_plot_window_)
+ { // External to plot window style.
+ if(y_label_rotation_ == horizontal)
+ { // Just shift down half a digit to center value digits on tick.
+ alignment = right_align;
+ y += y_label_value.font_size() / 2;
+ }
+ else if ((y_label_rotation_ == upward) || (y_label_rotation_ == downward))
+ {// Tick value label straight up or down vertically on y axis.
+ // No shift y down to center.
+ alignment = center_align;
+ }
+ else
+ { // Assume some 45 slope, so need about sqrt(2) less space?
+ x1 += y_label_value.font_size() * 0.5; // move left by half a font width.
+ // no y shift needed.
+ alignment = right_align;
+ }
+ // Always want all values including "0", if labeling external to plot window.
+ // use_ticks_on_plot_window_ == true
+ image.get_g_element(detail::PLOT_VALUE_LABELS).text(
+ x1,
+ y,
+ label.str(), y_label_value.font_size(), "", "", "", "", "", alignment, y_label_rotation_);
+ }
+ else
+ { // ! 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 if it would be cut through by any horizontal X-axis line.
+ 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(), "", "", "", "",
+ alignment, // on the tick ???
+ y_label_rotation_);
+ }
+ }
+ } // if(use_y_major_labels)
+ } // draw_y_major_ticks
+
+ void draw_y_minor_ticks(double value, path_element& tick_path, path_element& grid_path)
+ {
+ double x1(0.);
+ double y1(value); // for tick position and value label.
+ transform_y(y1);
+ double x2(image.y_size()); // right edge of image.
+
+ if(use_y_minor_grid_)
+ { // Draw the minor grid, if wanted.
+ if(!use_plot_window_)
+ { // Use whole image, but make space for title & labels text.
+ //if(use_title)
+ //{ // If title at top, should make no difference, unlike X grid.
+ // 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_;
+ }
+ }
+ else
+ { // Use plot window.
+ x1 = plot_x1 + 1; // TODO what is the +1 for?
+ x2 = plot_x2 - 1; // Ensure *inside* window?
+ }
+ if((y1 >= plot_y1) && (x1 >= plot_x1) && (x2 <= plot_x2) )
+ { // // Make sure that we are drawing inside the allowed window.
+ grid_path.M(x1, y1).L(x2, y1);
+ }
+ // TODO else just ignore outside plot window?
+ }
+
+ if(use_y_ticks_on_plot_window_)
+ { // Put y minor ticks on the plot window border. External style.
+ x1 = plot_x1; // On the plot window border.
+ x2 = plot_x1;
}
else
- { // Assume some slope, say 45, so * sin(45) = 0.707.
- l *= sin45;
+ { // Internal style.
+ x1 = y_axis; // On the Y-axis line.
+ x2 = y_axis;
+ }
+ if(use_left_ticks)
+ {
+ x1 -= y_minor_tick_length_;
+ }
+ if(use_right_ticks)
+ {
+ x2 += y_minor_tick_length_;
+ }
+ //if((x1 >= plot_x1) && (x2 <= plot_x2) && (y1 <= plot_y2) && (y1 >= plot_y1))
+ // but can never be inside if left tick!
+ if((y1 <= plot_y2) && (y1 >= plot_y1))
+ { // Make sure that we are drawing inside of the allowed plot window.
+ tick_path.M(x1, y1).L(x2, y1); // Draw the tick.
}
+ else
+ {// Do nothing? warn?
+ // std::cout << "y minor tick OUTside " << x1 << ' ' << y1 << ' ' << x2 << std::endl;
+
+ }
+ } // void draw_y_minor_ticks
+
+ void draw_straight_lines(const svg_2d_plot_series& series)
+ { // Straight line between data points (rather than a Bezier curve).
+ double prev_x; // Previous data points.
+ double prev_y;
+ double temp_x(0.);
+ double temp_y;
+
+ g_element& g_ptr = image.get_g_element(detail::PLOT_DATA_LINES).add_g_element();
+ g_ptr.clip_id(plot_window_clip);
+ g_ptr.style().stroke_color(series.line_style.color);
+ g_ptr.style().fill_color(series.line_style.area_fill);
+ path_element& path = g_ptr.path();
+ path.style().fill_color(series.line_style.area_fill);
+
+ bool is_fill = !series.line_style.area_fill.blank;
+ path.fill = is_fill; // Ensure includes a fill="none".
+
+ if(series.series.size() > 1)
+ {
+ std::multimap<double, double>::const_iterator j = series.series.begin();
+
+ // 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;
+ prev_y = 0.;
+ transform_point(prev_x, prev_y);
+ if(is_fill)
+ { // Move to 1st point.
+ path.style().fill_color(series.line_style.area_fill);
+ path.M(prev_x, prev_y);
+ }
+ transform_y(prev_y = (*j).second);
+ if(is_fill)
+ { // fill wanted.
+ path.style().fill_color(series.line_style.area_fill); // TOD why again?
+ path.L(prev_x, prev_y); // Line from X-axis to 1st point.
+ }
+ else
+ { // fill == blank
+ path.M(prev_x, prev_y);
+ }
+ ++j; // so now refers to 2nd point to plot.
+
+ for(; j != series.series.end(); ++j)
+ {
+ temp_x = (*j).first;
+ temp_y = (*j).second;
+ transform_point(temp_x, temp_y);
+ path.L(temp_x, temp_y); // line to next point.
+
+ if(is_fill)
+ {
+ path.M(temp_x, temp_y);
+ }
+ prev_x = temp_x;
+ prev_y = temp_y;
+ } // for j
+
+ if(is_fill)
+ { // fill wanted.
+ transform_y(temp_y = 0.); // X-axis line.
+ path.L(temp_x, temp_y).z(); // closepath with Z to terminate line.
+ }
+ }
+ } // draw_straight_lines
+
+ void draw_bezier_lines(const svg_2d_plot_series& series)
+ {
+ g_element& g_ptr = image.get_g_element(detail::PLOT_DATA_LINES).add_g_element();
+ g_ptr.clip_id(plot_window_clip);
+ g_ptr.style().stroke_color(series.line_style.color);
+ path_element& path = g_ptr.path();
+
+ 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;
+
+ bool is_fill = !series.line_style.area_fill.blank;
+ if(is_fill == false)
+ {
+ path.fill = false; // default path constructor is true - TODO why??
+ }
+ else
+ { // fill
+ path.style().fill_color(series.line_style.area_fill);
+ }
+
+ if(series.series.size() > 2)
+ { // 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++); // begin()
+ transform_pair(n_minus_1);
+ n = *(iter++); // middle
+ transform_pair(n);
+ 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_1 = n;
+ n = *iter;
+ transform_pair(n);
+
+ 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).
+ // 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!
+ draw_straight_lines(series);
+ }
+ } // draw_bezier_lines
+
+ void draw_plot_lines()
+ { // Draw line through data series, Bezier curved or straight.
+ for(unsigned int i = 0; i < series.size(); ++i)
+ {
+ if(series[i].line_style.bezier_on)
+ { // curved.
+ draw_bezier_lines(series[i]);
+ }
+ else
+ {
+ draw_straight_lines(series[i]);
+ }
+ }
+ } // draw_plot_lines
+
+ void update_image()
+ {
+ clear_all();
+ // svg paint rules are that later 'painting' writes over previous
+ // painting, so the order of drawing is important.
+
+ // Draw image background (perhaps with border and/or fill color).
+ image.get_g_element(detail::PLOT_BACKGROUND).push_back(
+ new rect_element(0, 0, image.x_size(), image.y_size()));
+
+ calculate_plot_window();
+ 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,
+ // thus the minor adjustments.
+ // TODO should this be border thickness?
+
+ image.clip_path(rect_element(plot_x1 + 1, plot_y1 + 1,
+ plot_x2 - plot_x1 - 2, plot_y2 - plot_y1 - 2),
+ plot_window_clip);
+ // <clipPath id="plot_window"><rect x="35" y="38" width="309" height="322"/></clipPath>
+
+ image.get_g_element(detail::PLOT_DATA_POINTS).clip_id(plot_window_clip);
+
+ // Draw axes, labels & legend, as required.
+ if(use_axis)
+ {
+ draw_x_axis(); // Must do X-axis first.
+ draw_y_axis(); // TODO is draw_axes used?
+ }
+ if(use_legend)
+ {
+ draw_legend();
+ }
+ if(use_x_label)
+ {
+ draw_x_label();
+ }
+ if(use_y_label)
+ {
+ draw_y_label();
+ }
+
+ draw_plot_lines(); // Draw lines between points.
+
+ // Draw normal 'good' non-limit points.
+ double x(0.);
+ double y(0.);
+ for(unsigned int i = 0; i < series.size(); ++i)
+ {
+ 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_);
+
+ for(std::multimap<double, double>::const_iterator j = series[i].series.begin();
+ j != series[i].series.end(); ++j)
+ {
+ x = j->first;
+ y = j->second;
+ transform_point(x, y);
+ if((x > plot_x1) && (x < plot_x2) && (y > plot_y1) && (y < plot_y2))
+ { // Onside plot window, so draw a point.
+ draw_plot_point(x, y, g_ptr, series[i].point_style);
+ }
+ } // for
+ } // for normal points
+
+ // Draw all the 'bad' at_limit points.
+ for(unsigned int i = 0; i < series.size(); ++i)
+ {
+ g_element& g_ptr = image.get_g_element(detail::PLOT_LIMIT_POINTS);
+
+ for(std::multimap<double,double>::const_iterator j = series[i].series_limits.begin();
+ j!=series[i].series_limits.end(); ++j)
+ {
+ 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));
+ // TODO why are fill and stroke blank? How is point style for 'bad' values determined?
+ }
+ } // limits point
+ } // void update_image()
+
+
+ public: // Member functions
+ // -----------------------------------------------------------------
+ // write() has two flavors, a file and a ostream.
+ // The file version opens an ostream, and calls the stream version.
+ // The stream version first clears all unnecessary data from the graph,
+ // builds the document tree, and then calls the write function for the root
+ // document node, which calls all other nodes through the Visitor pattern.
+ // -----------------------------------------------------------------
+
+ svg_2d_plot& write(const std::string& filename)
+ { // Write the plot image to a named file.
+ std::ofstream fout(filename.c_str());
+ if(fout.fail())
+ {
+ throw std::runtime_error("Unable to open " + filename);
+ }
+ write(fout); // Using the ostream version.
+ return *this;
}
- plot_y2 -= x_label_value.font_size() * l * wh_; // Move up.
- }
- if(use_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!
- }
- if(use_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_);
- }
+ svg_2d_plot& write(std::ostream& s_out)
+ { // Write the image to an ostream.
+ update_image();
+ image.write(s_out); // Use the ostream version of write.
+ return *this;
+ }
- if (use_x_axis_lines_)
- { // Want a X-axis line, so check if range include zero, so axes intersect,
- // and x_axis is svg coordinate of Y-axis (usually y = 0).
- // If not fix axis to bottom of the plot window
- // and leave space (and quiggle between) to show this.
- if (x_axis_position_ == bottom) // All definitely > zero.
- { // y_min > 0 so X-axis will not intersect Y-axis, so use plot window.
- x_axis = plot_y2; // X-axis to bottom,
- //plot_y2 -= 2 * y_label_info.font_size(); // with a space.
- }
- else if(x_axis_position_ == top) // definitely < zero.
- { // // y_max < 0 so X-axis will not intersect Y-axis, so use plot window.
- x_axis = plot_y1; // X-axis to top,
- //plot_y1 += 2 * y_label_info.font_size(); // with a space.
- }
- else
- { // y_axis_position_ == y_intersect
- // Calculate below after transform is calculated.
- }
- } // if (use_x_axis_)
-
- if (use_y_axis_lines_)
- { // Want a Y-axis line, so check if range include zero, so axes intersect,
- // and y_axis is svg coordinate of X-axis (usually x = 0).
- // If not fix axis to left of the plot window
- // and leave space (and quiggle between) to show this.
- if (y_axis_position_ == left) // all definitely > zero.
- { // Y-axis will not intersect X -axis, so put Y-axis line to left of plot window.
- y_axis = plot_x1; // Y-axis to left,
- //plot_x1 += 2 * y_label_info.font_size(); // with a space.
- }
- else if(y_axis_position_ == right)
- {
- y_axis = plot_x2; // Y-axis to right of plot window,
- //plot_x2 -= 2 * y_label_info.font_size(); // with a space.
- }
- else
- { // x_axis_position_ == x_intersect
- // Calculate below after transform is calculated.
- }
- } // if (use_y_axis_)
-
-
- // Calculate scale and shift factors for transform from Cartesian to plot.
- // SVG image is 0, 0 at top left,y increase *downwards*
- // Cartesian 0, 0 at bottom left, y increasing upwards.
- x_scale = (plot_x2 - plot_x1) / (x_max - x_min);
- x_shift = plot_x1 - x_min *(plot_x2 - plot_x1) / (x_max - x_min);
- y_scale = -(plot_y2-plot_y1) / (y_max-y_min);
- y_shift = plot_y1 - (y_max * (plot_y1 - plot_y2) / (y_max - y_min));
+ // Member functions to set plot options.
+ // All return *this to permit chaining.
- if (use_x_axis_lines_)
- {
- if(x_axis_position_ == x_intersect)
- { // Y Range *does* include zero, so x_axis not yet calculated.
- double y(0.); // Use y = 0
- transform_y(y);
- x_axis = y; // svg Y coordinate of horizontal X-axis line.
+ // These below only refer to 2D plot.
+ // See axis_plot_label.hpp for all the many 1D functions X-Axis.
+
+ svg_2d_plot& y_label_on(bool cmd)
+ { // Y axis name or label.
+ use_y_label = cmd;
+ return *this;
}
- }
- if (use_y_axis_lines_)
- { // May need to calculate axes, if will intersect.
- if(y_axis_position_ == y_intersect)
- { // X Range *does* include zero, so y_axis not yet calculated.
- double x(0.);
- transform_x(x);
- y_axis = x; // SVG x coordinate of vertical Y-axis.
+
+ bool y_label_on()
+ {
+ return use_y_label;
}
- }
- if (use_plot_window_)
- { // Draw plot window rectangle with background and/or border.
- image.get_g_element(detail::PLOT_WINDOW_BACKGROUND).push_back(
- new rect_element(plot_x1, plot_y1, (plot_x2 - plot_x1), plot_y2 - plot_y1));
- }
- } // calculate_plot_window
+ svg_2d_plot& x_label_on(bool cmd)
+ {
+ use_x_label = cmd;
+ return *this;
+ }
- void draw_y_axis()
- {
- double x;
- x = y_axis; // Y-axis (x = 0) transformed into X SVG coordinates.
- // Perhaps shifted to left or right if origin is missing.
-
- if(use_y_axis_lines_)
- { // Draw the vertical Y-axis line (at cartesian x = 0).
- double ybottom = plot_y2;
- if (use_down_ticks && use_y_ticks_on_plot_window_ && (x_axis_position_ == x_intersect) )
- { // Extend the vertical line down in lieu of a tick.
- ybottom += (std::max)(x_minor_tick_length_, x_major_tick_length_);
+ bool x_label_on()
+ {
+ return use_x_label;
}
- image.get_g_element(detail::PLOT_Y_AXIS).line(x, plot_y1, x, 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.
- path_element& minor_tick_path = image.get_g_element(detail::PLOT_Y_MINOR_TICKS).path();
- path_element& major_tick_path = image.get_g_element(detail::PLOT_Y_MAJOR_TICKS).path();
- path_element& minor_grid_path = image.get_g_element(detail::PLOT_Y_MINOR_GRID).path();
- path_element& major_grid_path = image.get_g_element(detail::PLOT_Y_MAJOR_GRID).path();
-
- if(use_y_ticks_on_plot_window_)
- { // TODO ensure that labels allow space. - they don't at present.
- // Was y_external style - so both labels and ticks are OUTSIDE the plot window.
- //
- }
- // y_minor_jump is the interval between minor ticks.
- double y_minor_jump = y_major_interval_ / ((double)(y_num_minor_ticks_ + 1.) );
- // TODO Problem here with 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 ls or few bits out? Seems to fail for y = 100, for example.
+ svg_2d_plot& y_major_labels_on(bool cmd)
+ {
+ use_y_major_labels = cmd;
+ return *this;
+ }
- // Draw the ticks on the positive side.
- for(double y = 0; y <= y_max; y += y_major_interval_)
- {
- 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.
- // These are just ignored in draw_x_minor_ticks.
- // 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.
- 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);
+ bool y_major_labels_on()
+ {
+ return use_y_major_labels;
}
- }
- // Draw the ticks on the negative side.
- for(double y = 0; y >= y_min; y -= y_major_interval_)
- {
- for(double j=y; j > y-y_major_interval_; j-= y_major_interval_ / (y_num_minor_ticks_ + 1))
- { // Draw minor ticks.
- 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);
- }
+ svg_2d_plot& y_major_label_rotation(int rot)
+ {
+ y_label_rotation_ = rot;
+ return *this;
}
- 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);
+
+ int y_major_label_rotation()
+ {
+ return y_label_rotation_;
}
- }
- } // draw_y_axis
- void draw_y_label()
- {
- // image.get_g_element(detail::PLOT_Y_LABEL).style().stroke_color(black);
- // Now set in constructor, and can be changed with member function .
-
- std::string label = y_label_info.text(); // x_axis label, and optional units.
- if (use_x_label_units && (y_units_info.text() != ""))
- { // Append the units, if any, providing brackets ().
- // TODO Is this the best policy - or should the user provide the ()s????
- label += " (" + y_units_info.text() + ")";
- }
+ svg_2d_plot& y_axis_width(double width)
+ {
+ image.get_g_element(detail::PLOT_Y_AXIS).style().stroke_width(width);
+ return *this;
+ }
- image.get_g_element(detail::PLOT_Y_LABEL).push_back(new
- text_element(y_label_info.font_size() * 1.5,
- // shift over one char height to right from left edge of image.
- (plot_y2 + plot_y1) / 2., // center on the plot window.
- label, // "Y-Axis" for example.
- y_label_info.font_size(),
- y_label_info.font_family(),
- "", "", "", "",
- center_align, // One might want it to left or right_align?
- upward)); // Y label must be drawn vertically.
- } // draw_y_label
-
- void draw_y_major_ticks(double value, path_element& tick_path, path_element& grid_path)
- { // Draw Y axis major ticks, tick value labels & grids.
- double y1(value);
- transform_y(y1); // cartesian to SVG coordinates.
- double x1(0.); // left end of tick.
- double x2(image.y_size()); // right end of tick.
- if(use_y_major_grid_)
- { // Draw horizontal major grid line.
- if(!use_plot_window_)
- { // TODO is this right?
- //if (use_title())
- //{ // title has no effect if at the top.
- // y1 += title_info.font_size() * text_margin_;
- //}
- if(use_y_label)
- { // Start further right to give space for y axis value label.
- y1 -= y_label_value.font_size() * text_margin_ ;
- }
+ double y_axis_width()
+ {
+ return image.get_g_element(detail::PLOT_Y_AXIS).style().stroke_width();
+ }
- if(use_left_ticks)
- { // And similarly for left ticks.
- y1 -= y_major_tick_length_;
- }
+ svg_2d_plot& y_value_precision(int digits)
+ { // Precision of Y tick label values in decimal digits (default 3).
+ y_value_precision_ = digits;
+ return *this;
+ }
+
+ int y_value_precision()
+ { // Precision of Y tick label values in decimal digits (default 3).
+ return y_value_precision_;
}
- else
- { // Do use_plot_window.
- x1 = plot_x1 + 1;
- x2 = plot_x2 - 1;
+
+ svg_2d_plot& y_value_ioflags(int flags)
+ { // IO flags of Y tick label values (default 0X201).
+ y_value_ioflags_ = flags;
+ return *this;
}
- 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_;
- if(use_y_ticks_on_plot_window_) // (was external_style)
- { // Start ticks on the plot window border.
- x1 = plot_x1; // x1 = left,
- x2 = plot_x1; // x2 = right.
+ int y_value_ioflags()
+ { // ALL stream ioflags for control of format of Y value labels.
+ return y_value_ioflags_;
}
- else
- { // Internal style ticks on vertical Y-axis.
- x1 = y_axis; // Y-axis line.
- x2 = y_axis;
+
+ svg_2d_plot& y_axis_color(const svg_color& col)
+ { // Set only stroke color.
+ image.get_g_element(detail::PLOT_Y_AXIS).style().stroke_color(col);
+ return *this;
}
- if(use_left_ticks)
+
+ svg_color y_axis_color()
+ { // return the stroke color.
+ return image.get_g_element(detail::PLOT_Y_AXIS).style().stroke_color();
+ }
+
+ svg_2d_plot& y_axis_label_color(const svg_color& col)
+ { // Set BOTH stroke and fill to the same color.
+ image.get_g_element(detail::PLOT_VALUE_LABELS).style().fill_color(col);
+ image.get_g_element(detail::PLOT_VALUE_LABELS).style().stroke_color(col);
+ return *this;
+ }
+
+ svg_color y_axis_label_color()
+ { // But only return the stroke color.
+ return image.get_g_element(detail::PLOT_VALUE_LABELS).style().stroke_color();
+ }
+
+ svg_2d_plot& y_label_units_on(bool b)
{
- x1 -= y_tick_length; // left
+ use_y_label_units = b;
+ return *this;
}
- if (use_right_ticks)
+
+ bool y_label_units_on()
+ { // But only return the stroke color.
+ return use_y_label_units;
+ }
+
+ svg_2d_plot& y_axis_value_color(const svg_color& col)
+ { // Set BOTH stroke and fill to the same color. TODO only stroke color?
+ image.get_g_element(detail::PLOT_VALUE_LABELS).style().fill_color(col);
+ image.get_g_element(detail::PLOT_VALUE_LABELS).style().stroke_color(col);
+ return *this;
+ }
+
+ svg_color y_axis_value_color()
+ { // But only return the stroke color.
+ return image.get_g_element(detail::PLOT_VALUE_LABELS).style().stroke_color();
+ }
+
+ svg_2d_plot& y_label_width(double width)
+ { // width of text is effectively the boldness
+ image.get_g_element(detail::PLOT_Y_LABEL).style().stroke_width(width);
+ return *this;
+ }
+
+ double y_label_width()
{
- x2 += y_tick_length; // right.
+ return image.get_g_element(detail::PLOT_Y_LABEL).style().stroke_width();
}
- tick_path.M(x1, y1).L(x2, y1); // Draw the major tick.
- // leaving x1 at the left most end of any tick.
- }
- if(use_y_major_labels)
- { // Label the tick with value, for example "1.2"
- std::stringstream label;
- label.precision(y_value_precision_);
- label.flags(y_value_ioflags_); // set ALL IOflags.
- label << value; // Example: label.str() == "20" or "0.25" or "1.2e+015"
- if(use_left_ticks)
- {
- if (y_minor_tick_length_ > y_minor_tick_length_)
- { // In case some joker has made the minor ticks longer than the major,
- // we might need to move left more for the longer tick.
- x1 -= (y_minor_tick_length_ - y_minor_tick_length_);
- }
- x1 -= y_label_value.font_size(); // move left by a font width.
- }
- else
- { // No need to move if right tick, or none.
- }
- // Need to work out how much space value labels will need.
- double y = y1;
- align_style alignment = center_align;
- if(use_y_ticks_on_plot_window_)
- { // External to plot window style.
- if(y_label_rotation_ == horizontal)
- { // Just shift down half a digit to center value digits on tick.
- alignment = right_align;
- y += y_label_value.font_size() / 2;
- }
- else if ((y_label_rotation_ == upward) || (y_label_rotation_ == downward))
- {// Tick value label straight up or down vertically on y axis.
- // No shift y down to center.
- alignment = center_align;
- }
- else
- { // Assume some 45 slope, so need about sqrt(2) less space?
- x1 += y_label_value.font_size() * 0.5; // move left by half a font width.
- // no y shift needed.
- alignment = right_align;
- }
- // Always want all values including "0", if labeling external to plot window.
- // use_ticks_on_plot_window_ == true
- image.get_g_element(detail::PLOT_VALUE_LABELS).text(
- x1,
- y,
- label.str(), y_label_value.font_size(), "", "", "", "", "", alignment, y_label_rotation_);
- }
- else
- { // ! 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 if it would be cut through by any horizontal X-axis line.
- 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(), "", "", "", "",
- alignment, // on the tick ???
- y_label_rotation_);
- }
+ svg_2d_plot& y_major_grid_color(const svg_color& col)
+ {
+ image.get_g_element(detail::PLOT_Y_MAJOR_GRID).style().stroke_color(col);
+ return *this;
}
- } // if(use_y_major_labels)
- } // draw_y_major_ticks
- void draw_y_minor_ticks(double value, path_element& tick_path, path_element& grid_path)
- {
- double x1(0.);
- double y1(value); // for tick position and value label.
- transform_y(y1);
- double x2(image.y_size()); // right edge of image.
-
- if(use_y_minor_grid_)
- { // Draw the minor grid, if wanted.
- if(!use_plot_window_)
- { // Use whole image, but make space for title & labels text.
- //if(use_title)
- //{ // If title at top, should make no difference, unlike X grid.
- // x2 -= title_info.font_size() * text_margin_;
- //}
- if(use_y_label)
+ const svg_color& y_major_grid_color()
+ {
+ return image.get_g_element(detail::PLOT_Y_MAJOR_GRID).style().stroke_color();
+ }
+
+ svg_2d_plot& y_minor_grid_color(const svg_color& col)
+ {
+ image.get_g_element(detail::PLOT_Y_MINOR_GRID).style().stroke_color(col);
+ return *this;
+ }
+
+ const svg_color& y_minor_grid_color()
+ {
+ return image.get_g_element(detail::PLOT_Y_MINOR_GRID).style().stroke_color();
+ }
+
+ svg_2d_plot& y_major_tick_color(const svg_color& col)
+ {
+ image.get_g_element(detail::PLOT_Y_MAJOR_TICKS).style().stroke_color(col);
+ return *this;
+ }
+
+ const svg_color& y_major_tick_color()
+ {
+ return image.get_g_element(detail::PLOT_Y_MAJOR_TICKS).style().stroke_color();
+ }
+
+ svg_2d_plot& y_minor_tick_color(const svg_color& col)
+ {
+ image.get_g_element(detail::PLOT_Y_MINOR_TICKS).style().stroke_color(col);
+ return *this;
+ }
+
+ const svg_color& y_minor_tick_color()
+ {
+ return image.get_g_element(detail::PLOT_Y_MINOR_TICKS).style().stroke_color();
+ }
+
+ svg_2d_plot& y_range(double y1, double y2)
+ { // Set the range (max and min) for Y values.
+ y_min = y1;
+ y_max = y2;
+ if(y2 <= y1)
{
- x1 += y_label_info.font_size() * text_margin_;
- x2 -= y_label_info.font_size() * text_margin_;
+ throw std::runtime_error("Illegal Argument: X scale: x2 < x1");
}
+ return *this;
}
- else
- { // Use plot window.
- x1 = plot_x1 + 1; // TODO what is the +1 for?
- x2 = plot_x2 - 1; // Ensure *inside* window?
+
+ std::pair<double, double> y_range()
+ {
+ std::pair<double, double> r;
+ r.first = y_min;
+ r.second = y_max;
+ return r;
}
- if((y1 >= plot_y1) && (x1 >= plot_x1) && (x2 <= plot_x2) )
- { // // Make sure that we are drawing inside the allowed window.
- grid_path.M(x1, y1).L(x2, y1);
+
+ double y_minimum()
+ {
+ return y_min;
}
- // TODO else just ignore outside plot window?
- }
- if(use_y_ticks_on_plot_window_)
- { // Put y minor ticks on the plot window border. External style.
- x1 = plot_x1; // On the plot window border.
- x2 = plot_x1;
- }
- else
- { // Internal style.
- x1 = y_axis; // On the Y-axis line.
- x2 = y_axis;
- }
- if(use_left_ticks)
- {
- x1 -= y_minor_tick_length_;
- }
- if(use_right_ticks)
- {
- x2 += y_minor_tick_length_;
- }
- //if((x1 >= plot_x1) && (x2 <= plot_x2) && (y1 <= plot_y2) && (y1 >= plot_y1))
- // but can never be inside if left tick!
- if((y1 <= plot_y2) && (y1 >= plot_y1))
- { // Make sure that we are drawing inside of the allowed plot window.
- tick_path.M(x1, y1).L(x2, y1); // Draw the tick.
- }
- else
- {// Do nothing? warn?
- // std::cout << "y minor tick OUTside " << x1 << ' ' << y1 << ' ' << x2 << std::endl;
+ double y_maximum()
+ {
+ return y_max;
+ }
- }
- } // void draw_y_minor_ticks
+ svg_2d_plot& y_major_interval(double inter)
+ {
+ y_major_interval_ = inter;
+ return *this;
+ }
- void draw_straight_lines(const svg_2d_plot_series& series)
- { // Straight line between data points (rather than a Bezier curve).
- double prev_x; // Previous data points.
- double prev_y;
- double temp_x(0.);
- double temp_y;
-
- g_element& g_ptr = image.get_g_element(detail::PLOT_DATA_LINES).add_g_element();
- g_ptr.clip_id(plot_window_clip);
- g_ptr.style().stroke_color(series.line_style.color);
- g_ptr.style().fill_color(series.line_style.area_fill);
- path_element& path = g_ptr.path();
- path.style().fill_color(series.line_style.area_fill);
+ double y_major_interval()
+ {
+ return y_major_interval_;
+ }
- bool is_fill = !series.line_style.area_fill.blank;
- path.fill = is_fill; // Ensure includes a fill="none".
+ svg_2d_plot& y_major_tick_length(double length)
+ {
+ y_major_tick_length_ = length;
+ return *this;
+ }
- if(series.series.size() > 1)
- {
- std::multimap<double, double>::const_iterator j = series.series.begin();
+ double y_major_tick_length()
+ {
+ return y_major_tick_length_;
+ }
- // 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;
- prev_y = 0.;
- transform_point(prev_x, prev_y);
- if(is_fill)
- { // Move to 1st point.
- path.style().fill_color(series.line_style.area_fill);
- path.M(prev_x, prev_y);
+ svg_2d_plot& y_minor_tick_length(double length)
+ {
+ y_minor_tick_length_ = length;
+ return *this;
}
- transform_y(prev_y = (*j).second);
- if(is_fill)
- { // fill wanted.
- path.style().fill_color(series.line_style.area_fill); // TOD why again?
- path.L(prev_x, prev_y); // Line from X-axis to 1st point.
+
+ double y_minor_tick_length()
+ {
+ return y_minor_tick_length_;
}
- else
- { // fill == blank
- path.M(prev_x, prev_y);
+
+ svg_2d_plot& y_num_minor_ticks(unsigned int num)
+ {
+ y_num_minor_ticks_ = num;
+ return *this;
}
- ++j; // so now refers to 2nd point to plot.
- for(; j != series.series.end(); ++j)
+ unsigned int y_num_minor_ticks()
{
- temp_x = (*j).first;
- temp_y = (*j).second;
- transform_point(temp_x, temp_y);
- path.L(temp_x, temp_y); // line to next point.
+ return y_num_minor_ticks_;
+ }
- if(is_fill)
- {
- path.M(temp_x, temp_y);
- }
- prev_x = temp_x;
- prev_y = temp_y;
- } // for j
+ svg_2d_plot& y_label_axis(const std::string& str)
+ { // Label for Y-axis.
+ y_label_info.text(str);
+ return *this;
+ }
- if(is_fill)
- { // fill wanted.
- transform_y(temp_y = 0.); // X-axis line.
- path.L(temp_x, temp_y).z(); // closepath with Z to terminate line.
+ std::string y_label_axis()
+ {
+ return y_label_info.text();
}
- }
- } // draw_straight_lines
- void draw_bezier_lines(const svg_2d_plot_series& series)
- {
- g_element& g_ptr = image.get_g_element(detail::PLOT_DATA_LINES).add_g_element();
- g_ptr.clip_id(plot_window_clip);
- g_ptr.style().stroke_color(series.line_style.color);
- path_element& path = g_ptr.path();
-
- 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;
+ svg_2d_plot& y_major_tick_width(double width)
+ {
+ y_major_tick_width_ = width;
+ image.get_g_element(detail::PLOT_Y_MAJOR_TICKS).style().stroke_width(width);
+ return *this;
+ }
- bool is_fill = !series.line_style.area_fill.blank;
- if(is_fill == false)
- {
- path.fill = false; // default path constructor is true - TODO why??
- }
- else
- { // fill
- path.style().fill_color(series.line_style.area_fill);
- }
+ double y_major_tick_width()
+ {
+ return y_major_tick_width_;
+ }
- if(series.series.size() > 2)
- { // 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++); // begin()
- transform_pair(n_minus_1);
- n = *(iter++); // middle
- transform_pair(n);
- 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_1 = n;
- n = *iter;
- transform_pair(n);
-
- 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).
- // 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!
- draw_straight_lines(series);
- }
- } // draw_bezier_lines
+ svg_2d_plot& y_minor_tick_width(double width)
+ {
+ y_minor_tick_width_ = width;
+ image.get_g_element(detail::PLOT_Y_MINOR_TICKS).style().stroke_width(width);
+ return *this;
+ }
- void draw_plot_lines()
- { // Draw line through data series, Bezier curved or straight.
- for(unsigned int i = 0; i < series.size(); ++i)
- {
- if(series[i].line_style.bezier_on)
- { // curved.
- draw_bezier_lines(series[i]);
+ double y_minor_tick_width()
+ {
+ return y_minor_tick_width_;
}
- else
+
+ svg_2d_plot& x_ticks_on_plot_window_on(bool is)
{
- draw_straight_lines(series[i]);
+ use_x_ticks_on_plot_window_ = is;
+ return *this;
}
- }
- } // draw_plot_lines
- void update_image()
- {
- clear_all();
- // svg paint rules are that later 'painting' writes over previous
- // painting, so the order of drawing is important.
-
- // Draw image background (perhaps with border and/or fill color).
- image.get_g_element(detail::PLOT_BACKGROUND).push_back(
- new rect_element(0, 0, image.x_size(), image.y_size()));
-
- calculate_plot_window();
- 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,
- // thus the minor adjustments.
- // TODO should this be border thickness?
-
- image.clip_path(rect_element(plot_x1 + 1, plot_y1 + 1,
- plot_x2 - plot_x1 - 2, plot_y2 - plot_y1 - 2),
- plot_window_clip);
- // <clipPath id="plot_window"><rect x="35" y="38" width="309" height="322"/></clipPath>
+ bool x_ticks_on_plot_window_on()
+ {
+ return use_x_ticks_on_plot_window_;
+ }
- image.get_g_element(detail::PLOT_DATA_POINTS).clip_id(plot_window_clip);
+ svg_2d_plot& y_ticks_on_plot_window_on(bool is)
+ {
+ use_y_ticks_on_plot_window_ = is;
+ return *this;
+ }
- // Draw axes, labels & legend, as required.
- if(use_axis)
- {
- draw_x_axis(); // Must do X-axis first.
- draw_y_axis(); // TODO is draw_axes used?
- }
- if(use_legend)
- {
- draw_legend();
- }
- if(use_x_label)
- {
- draw_x_label();
- }
- if(use_y_label)
- {
- draw_y_label();
- }
+ bool y_ticks_on_plot_window_on()
+ {
+ return use_y_ticks_on_plot_window_;
+ }
- draw_plot_lines(); // Draw lines between points.
- // Draw normal 'good' non-limit points.
- double x(0.);
- double y(0.);
- for(unsigned int i = 0; i < series.size(); ++i)
- {
- g_element& g_ptr = image.get_g_element(detail::PLOT_DATA_POINTS).add_g_element();
+ svg_2d_plot& y_ticks_left_on(bool cmd)
+ {
+ use_left_ticks = cmd;
+ return *this;
+ }
- g_ptr.style()
- .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)
- {
- x = j->first;
- y = j->second;
- transform_point(x, y);
- if((x > plot_x1) && (x < plot_x2) && (y > plot_y1) && (y < plot_y2))
- { // Onside plot window, so draw a point.
- draw_plot_point(x, y, g_ptr, series[i].point_style);
- }
- } // for
- } // for normal points
+ bool y_ticks_left_on()
+ {
+ return use_left_ticks;
+ }
- // Draw all the 'bad' at_limit points.
- for(unsigned int i = 0; i < series.size(); ++i)
- {
- g_element& g_ptr = image.get_g_element(detail::PLOT_LIMIT_POINTS);
+ svg_2d_plot& y_ticks_right_on(bool cmd)
+ {
+ use_right_ticks = cmd;
+ return *this;
+ }
- for(std::multimap<double,double>::const_iterator j = series[i].series_limits.begin();
- j!=series[i].series_limits.end(); ++j)
+ bool y_ticks_right_on()
{
- 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));
- // TODO why are fill and stroke blank? How is point style for 'bad' values determined?
- }
- } // limits point
- } // void update_image()
-
-
-public: // Member functions
- // -----------------------------------------------------------------
- // write() has two flavors, a file and a ostream.
- // The file version opens an ostream, and calls the stream version.
- // The stream version first clears all unnecessary data from the graph,
- // builds the document tree, and then calls the write function for the root
- // document node, which calls all other nodes through the Visitor pattern.
- // -----------------------------------------------------------------
-
- svg_2d_plot& write(const std::string& filename)
- { // Write the plot image to a named file.
- std::ofstream fout(filename.c_str());
- if(fout.fail())
- {
- throw std::runtime_error("Unable to open " + filename);
- }
- write(fout); // Using the ostream version.
- return *this;
- }
-
- svg_2d_plot& write(std::ostream& s_out)
- { // Write the image to an ostream.
- update_image();
- image.write(s_out); // Use the ostream version of write.
- return *this;
- }
-
- // Member functions to set plot options.
- // All return *this to permit chaining.
-
- // These below only refer to 2D plot.
- // See axis_plot_label.hpp for all the many 1D functions X-Axis.
-
- svg_2d_plot& y_label_on(bool cmd)
- { // Y axis name or label.
- use_y_label = cmd;
- return *this;
- }
-
- bool y_label_on()
- {
- return use_y_label;
- }
-
- svg_2d_plot& x_label_on(bool cmd)
- {
- use_x_label = cmd;
- return *this;
- }
-
- bool x_label_on()
- {
- return use_x_label;
- }
-
- svg_2d_plot& y_major_labels_on(bool cmd)
- {
- use_y_major_labels = cmd;
- return *this;
- }
-
- bool y_major_labels_on()
- {
- return use_y_major_labels;
- }
-
- svg_2d_plot& y_major_label_rotation(int rot)
- {
- y_label_rotation_ = rot;
- return *this;
- }
-
- int y_major_label_rotation()
- {
- return y_label_rotation_;
- }
-
- svg_2d_plot& y_axis_width(double width)
- {
- image.get_g_element(detail::PLOT_Y_AXIS).style().stroke_width(width);
- return *this;
- }
-
- double y_axis_width()
- {
- return image.get_g_element(detail::PLOT_Y_AXIS).style().stroke_width();
- }
-
- svg_2d_plot& y_value_precision(int digits)
- { // Precision of Y tick label values in decimal digits (default 3).
- y_value_precision_ = digits;
- return *this;
- }
-
- int y_value_precision()
- { // Precision of Y tick label values in decimal digits (default 3).
- return y_value_precision_;
- }
-
- svg_2d_plot& y_value_ioflags(int flags)
- { // IO flags of Y tick label values (default 0X201).
- y_value_ioflags_ = flags;
- return *this;
- }
-
- int y_value_ioflags()
- { // ALL stream ioflags for control of format of Y value labels.
- return y_value_ioflags_;
- }
-
- svg_2d_plot& y_axis_color(const svg_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()
- { // return the stroke color.
- return image.get_g_element(detail::PLOT_Y_AXIS).style().stroke_color();
- }
-
- svg_2d_plot& y_axis_label_color(const svg_color& col)
- { // Set BOTH stroke and fill to the same color.
- image.get_g_element(detail::PLOT_VALUE_LABELS).style().fill_color(col);
- image.get_g_element(detail::PLOT_VALUE_LABELS).style().stroke_color(col);
- return *this;
- }
-
- svg_color y_axis_label_color()
- { // But only return the stroke color.
- return image.get_g_element(detail::PLOT_VALUE_LABELS).style().stroke_color();
- }
-
- svg_2d_plot& y_label_units_on(bool b)
- {
- use_y_label_units = b;
- return *this;
- }
-
- bool y_label_units_on()
- { // But only return the stroke color.
- return use_y_label_units;
- }
-
- svg_2d_plot& y_axis_value_color(const svg_color& col)
- { // Set BOTH stroke and fill to the same color. TODO only stroke color?
- image.get_g_element(detail::PLOT_VALUE_LABELS).style().fill_color(col);
- image.get_g_element(detail::PLOT_VALUE_LABELS).style().stroke_color(col);
- return *this;
- }
-
- svg_color y_axis_value_color()
- { // But only return the stroke color.
- return image.get_g_element(detail::PLOT_VALUE_LABELS).style().stroke_color();
- }
-
- svg_2d_plot& y_label_width(double width)
- { // width of text is effectively the boldness
- image.get_g_element(detail::PLOT_Y_LABEL).style().stroke_width(width);
- return *this;
- }
-
- double y_label_width()
- {
- return image.get_g_element(detail::PLOT_Y_LABEL).style().stroke_width();
- }
-
- svg_2d_plot& y_major_grid_color(const svg_color& col)
- {
- image.get_g_element(detail::PLOT_Y_MAJOR_GRID).style().stroke_color(col);
- return *this;
- }
-
- const svg_color& y_major_grid_color()
- {
- return image.get_g_element(detail::PLOT_Y_MAJOR_GRID).style().stroke_color();
- }
-
- svg_2d_plot& y_minor_grid_color(const svg_color& col)
- {
- image.get_g_element(detail::PLOT_Y_MINOR_GRID).style().stroke_color(col);
- return *this;
- }
-
- const svg_color& y_minor_grid_color()
- {
- return image.get_g_element(detail::PLOT_Y_MINOR_GRID).style().stroke_color();
- }
-
- svg_2d_plot& y_major_tick_color(const svg_color& col)
- {
- image.get_g_element(detail::PLOT_Y_MAJOR_TICKS).style().stroke_color(col);
- return *this;
- }
-
- const svg_color& y_major_tick_color()
- {
- return image.get_g_element(detail::PLOT_Y_MAJOR_TICKS).style().stroke_color();
- }
-
- svg_2d_plot& y_minor_tick_color(const svg_color& col)
- {
- image.get_g_element(detail::PLOT_Y_MINOR_TICKS).style().stroke_color(col);
- return *this;
- }
-
- const svg_color& y_minor_tick_color()
- {
- return image.get_g_element(detail::PLOT_Y_MINOR_TICKS).style().stroke_color();
- }
-
- svg_2d_plot& y_range(double y1, double y2)
- { // Set the range (max and min) for Y values.
- y_min = y1;
- y_max = y2;
- if(y2 <= y1)
- {
- throw std::runtime_error("Illegal Argument: X scale: x2 < x1");
- }
- return *this;
- }
+ return use_right_ticks;
+ }
+ // Only need y_ticks_left_on & y_ticks_right_on in 2D
+
+
+ svg_2d_plot& y_major_grid_on(bool is)
+ {
+ use_y_major_grid_ = is;
+ return *this;
+ }
+
+ bool y_major_grid_on()
+ {
+ return use_y_major_grid_;
+ }
+
+ svg_2d_plot& y_minor_grid_on(bool is)
+ {
+ use_y_minor_grid_ = is;
+ return *this;
+ }
+
+ bool y_minor_grid_on()
+ {
+ return use_y_minor_grid_;
+ }
+
+ svg_2d_plot& y_minor_grid_width(double width)
+ {
+ y_minor_grid_width_ = width;
+ image.get_g_element(detail::PLOT_Y_MINOR_GRID).style().stroke_width(width);
+ return *this;
+ }
+
+ double y_minor_grid_width()
+ {
+ return y_minor_grid_width_;
+ }
+
+ svg_2d_plot& y_major_grid_width(double width)
+ {
+ y_major_grid_width_ = width;
+ image.get_g_element(detail::PLOT_Y_MAJOR_GRID).style().stroke_width(width);
+ return *this;
+ }
+
+ double y_major_grid_width()
+ {
+ return y_major_grid_width_;
+ }
+
+ svg_2d_plot& y_label_font_size(unsigned int i)
+ { // May be best to tie label & unit font sizes together?
+ y_label_info.font_size(i);
+ // y_units_info.font_size(i);
+ return *this;
+ }
+
+ unsigned int y_label_font_size()
+ {
+ 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;
+ }
- std::pair<double, double> y_range()
- {
- std::pair<double, double> r;
- r.first = y_min;
- r.second = y_max;
- return r;
- }
-
- double y_minimum()
- {
- return y_min;
- }
-
- double y_maximum()
- {
- return y_max;
- }
-
- svg_2d_plot& y_major_interval(double inter)
- {
- y_major_interval_ = inter;
- return *this;
- }
-
- double y_major_interval()
- {
- return y_major_interval_;
- }
-
- svg_2d_plot& y_major_tick_length(double length)
- {
- y_major_tick_length_ = length;
- return *this;
- }
-
- double y_major_tick_length()
- {
- return y_major_tick_length_;
- }
-
- svg_2d_plot& y_minor_tick_length(double length)
- {
- y_minor_tick_length_ = length;
- return *this;
- }
-
- double y_minor_tick_length()
- {
- return y_minor_tick_length_;
- }
-
- svg_2d_plot& y_num_minor_ticks(unsigned int num)
- {
- y_num_minor_ticks_ = num;
- return *this;
- }
-
- unsigned int y_num_minor_ticks()
- {
- return y_num_minor_ticks_;
- }
-
- svg_2d_plot& y_label_axis(const std::string& str)
- { // Label for Y-axis.
- y_label_info.text(str);
- return *this;
- }
-
- std::string y_label_axis()
- {
- return y_label_info.text();
- }
-
- svg_2d_plot& y_major_tick_width(double width)
- {
- y_major_tick_width_ = width;
- image.get_g_element(detail::PLOT_Y_MAJOR_TICKS).style().stroke_width(width);
- return *this;
- }
-
- double y_major_tick_width()
- {
- return y_major_tick_width_;
- }
-
- svg_2d_plot& y_minor_tick_width(double width)
- {
- y_minor_tick_width_ = width;
- image.get_g_element(detail::PLOT_Y_MINOR_TICKS).style().stroke_width(width);
- return *this;
- }
-
- double y_minor_tick_width()
- {
- return y_minor_tick_width_;
- }
-
- svg_2d_plot& x_ticks_on_plot_window_on(bool is)
- {
- use_x_ticks_on_plot_window_ = is;
- return *this;
- }
-
- bool x_ticks_on_plot_window_on()
- {
- return use_x_ticks_on_plot_window_;
- }
-
- svg_2d_plot& y_ticks_on_plot_window_on(bool is)
- {
- use_y_ticks_on_plot_window_ = is;
- return *this;
- }
-
- bool y_ticks_on_plot_window_on()
- {
- return use_y_ticks_on_plot_window_;
- }
-
-
- svg_2d_plot& y_ticks_left_on(bool cmd)
- {
- use_left_ticks = cmd;
- return *this;
- }
-
- bool y_ticks_left_on()
- {
- return use_left_ticks;
- }
-
- svg_2d_plot& y_ticks_right_on(bool cmd)
- {
- use_right_ticks = cmd;
- return *this;
- }
-
- bool y_ticks_right_on()
- {
- return use_right_ticks;
- }
- // Only need y_ticks_left_on & y_ticks_right_on in 2D
-
-
- svg_2d_plot& y_major_grid_on(bool is)
- {
- use_y_major_grid_ = is;
- return *this;
- }
-
- bool y_major_grid_on()
- {
- return use_y_major_grid_;
- }
-
- svg_2d_plot& y_minor_grid_on(bool is)
- {
- use_y_minor_grid_ = is;
- return *this;
- }
-
- bool y_minor_grid_on()
- {
- return use_y_minor_grid_;
- }
-
- svg_2d_plot& y_minor_grid_width(double width)
- {
- y_minor_grid_width_ = width;
- image.get_g_element(detail::PLOT_Y_MINOR_GRID).style().stroke_width(width);
- return *this;
- }
-
- double y_minor_grid_width()
- {
- return y_minor_grid_width_;
- }
-
- svg_2d_plot& y_major_grid_width(double width)
- {
- y_major_grid_width_ = width;
- image.get_g_element(detail::PLOT_Y_MAJOR_GRID).style().stroke_width(width);
- return *this;
- }
-
- double y_major_grid_width()
- {
- return y_major_grid_width_;
- }
-
- svg_2d_plot& y_label_font_size(unsigned int i)
- { // May be best to tie label & unit font sizes together?
- y_label_info.font_size(i);
- // y_units_info.font_size(i);
- return *this;
- }
-
- unsigned int y_label_font_size()
- {
- 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);
- return *this;
- }
-
- const std::string& y_label_font_family();
- //const std::string& y_label_font_family()
- //{
- // return y_label_info.font_family();
- //}
-
- // Example of declaration but definition below.
- // 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.
+ 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);
+ return *this;
+ }
+
+ const std::string& y_label_font_family();
+ //const std::string& y_label_font_family()
+ //{
+ // return y_label_info.font_family();
+ //}
+
+ // Example of declaration but definition below.
+ // 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.
#if defined (BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable: 4100) // "'boost_parameter_enabler_argument' : unreferenced formal parameter"
#endif
- BOOST_PARAMETER_MEMBER_FUNCTION
- (
- (void),
- plot,
- tag,
- (required
- (container, *)
- (title, (const std::string&))
- )
- (optional
- (fill_color, (const svg_color&), white)
- (stroke_color, (const svg_color&), black)
- (line_color, (const svg_color&), black)
- (area_fill_color, (const svg_color&), true) // == is blank
- // (area_fill_color, (svg_color_constant), blank)
- (point_style, (point_shape), round)
- (size, (int), 10)
- (line_on, (bool), true)
- (bezier_on, (bool), false)
- (x_functor, *, detail::boost_default_2d_convert())
- )
- )
- {
- // This line has the error in GCC. Also, operator() in boost_default_2d_convert
- // has been changed so that the value of i is not updated. I would like
- // the start to be set, as well as i to update in operator().
- // x_functor.start(1.);
-
- plot_line_style line_style(line_color, blank, line_on, bezier_on);
-
- line_style.area_fill = area_fill_color;
-
- series.push_back(
- svg_2d_plot_series(
- boost::make_transform_iterator(container.begin(), x_functor),
- boost::make_transform_iterator(container.end(), x_functor),
- title,
- plot_point_style(fill_color, stroke_color, size, point_style),
- line_style
- ));
- }
-}; // class svg_2d_plot : public detail::axis_plot_frame<svg_2d_plot>
-
-// 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();
- }
+ BOOST_PARAMETER_MEMBER_FUNCTION
+ (
+ (void),
+ plot,
+ tag,
+ (required
+ (container, *)
+ (title, (const std::string&))
+ )
+ (optional
+ (fill_color, (const svg_color&), white)
+ (stroke_color, (const svg_color&), black)
+ (line_color, (const svg_color&), black)
+ (area_fill_color, (const svg_color&), true) // == is blank
+ // (area_fill_color, (svg_color_constant), blank)
+ (point_style, (point_shape), round)
+ (size, (int), 10)
+ (line_on, (bool), true)
+ (bezier_on, (bool), false)
+ (x_functor, *, detail::boost_default_2d_convert())
+ )
+ )
+ {
+ // This line has the error in GCC. Also, operator() in boost_default_2d_convert
+ // has been changed so that the value of i is not updated. I would like
+ // the start to be set, as well as i to update in operator().
+ // x_functor.start(1.);
+
+ plot_line_style line_style(line_color, blank, line_on, bezier_on);
+
+ line_style.area_fill = area_fill_color;
+
+ series.push_back(
+ svg_2d_plot_series(
+ boost::make_transform_iterator(container.begin(), x_functor),
+ boost::make_transform_iterator(container.end(), x_functor),
+ title,
+ plot_point_style(fill_color, stroke_color, size, point_style),
+ line_style
+ ));
+ }
+ }; // class svg_2d_plot : public detail::axis_plot_frame<svg_2d_plot>
+
+ // 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();
+ }
#if defined (BOOST_MSVC)
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