# HG changeset patch # User Shai Ayal # Date 1202963609 -7200 # Node ID 3584f37eac698dcb061ab715e62464f84240289d # Parent 68550ad9ee9c104b6cde93b24280048f3e7bb3fd better tick and limit handling, still missing logscale support * * * better adjustments of ticks for manual limits diff -r 68550ad9ee9c -r 3584f37eac69 src/ChangeLog --- a/src/ChangeLog Tue Feb 12 16:37:56 2008 +0100 +++ b/src/ChangeLog Thu Feb 14 06:33:29 2008 +0200 @@ -1,3 +1,18 @@ +2008-06-04 Shai Ayal + + * graphics.cc (axes::properties::calc_ticks_and_lims): Refactor. + Adjust axes limits & tics together so that the result is consistent. + (axes::properties::calc_tick_sep): Ditto. + (axes::properties::get_axis_limits): Ditto. Now a member of + axes::properties + (magform): Now file-scope static function instead of + axes::properties member function. + + * graphics.h.in (axes::properties::update_xlim): call the new + axes::properties::calc_ticks_and_lims method + (axes::properties::update_ylim): ditto + (axes::properties::update_zlim): ditto + 2008-06-04 Michael Goffioul * genprops.awk: Add 'U' modifier to support extern updaters. diff -r 68550ad9ee9c -r 3584f37eac69 src/graphics.cc --- a/src/graphics.cc Tue Feb 12 16:37:56 2008 +0100 +++ b/src/graphics.cc Thu Feb 14 06:33:29 2008 +0200 @@ -2241,12 +2241,75 @@ min_pos = val; } +// magform(x) Returns (a, b), where x = a * 10^b, a >= 1., and b is +// integral. + +static void magform (double x, double& a, int& b) +{ + if (x == 0) + { + a = 0; + b = 0; + } + else + { + double l = std::log10 (std::abs (x)); + double r = std::fmod (l, 1.); + a = std::pow (10.0, r); + b = static_cast (l-r); + if (a < 1) + { + a *= 10; + b -= 1; + } + + if (x < 0) + a = -a; + } +} + +// A translation from Tom Holoryd's python code at +// http://kurage.nimh.nih.gov/tomh/tics.py +// FIXME -- add log ticks + +double +axes::properties::calc_tick_sep (double lo, double hi) +{ + int ticint = 5; + + // Reference: Lewart, C. R., "Algorithms SCALE1, SCALE2, and + // SCALE3 for Determination of Scales on Computer Generated + // Plots", Communications of the ACM, 10 (1973), 639-640. + // Also cited as ACM Algorithm 463. + + double a; + int b, x; + + magform ((hi-lo)/ticint, a, b); + + static const double sqrt_2 = sqrt (2.0); + static const double sqrt_10 = sqrt (10.0); + static const double sqrt_50 = sqrt (50.0); + + if (a < sqrt_2) + x = 1; + else if (a < sqrt_10) + x = 2; + else if (a < sqrt_50) + x = 5; + else + x = 10; + + return x * std::pow (10., b); + +} + // Attempt to make "nice" limits from the actual max and min of the // data. For log plots, we will also use the smallest strictly positive // value. -static Matrix -get_axis_limits (double xmin, double xmax, double min_pos, bool logscale) +Matrix +axes::properties::get_axis_limits (double xmin, double xmax, double min_pos, bool logscale) { Matrix retval; @@ -2290,10 +2353,10 @@ min_val -= 0.1 * std::abs (min_val); max_val += 0.1 * std::abs (max_val); } - // FIXME -- to do a better job, we should consider the tic spacing. - double scale = pow (10, floor (log10 (max_val - min_val) - 1)); - min_val = scale * floor (min_val / scale); - max_val = scale * ceil (max_val / scale); + + double tick_sep = calc_tick_sep (min_val , max_val); + min_val = tick_sep * std::floor (min_val / tick_sep); + max_val = tick_sep * ceil (max_val / tick_sep); } } @@ -2305,89 +2368,44 @@ return retval; } -// magform(x) Returns (a, b), where x = a * 10^b, a >= 1., and b is -// integral. - void -axes::properties::magform (double x, double& a, int& b) +axes::properties::calc_ticks_and_lims (array_property& lims, array_property& ticks, bool limmode_is_auto) { - if (x == 0) - { - a = 0; - b = 0; - } - else - { - double l = std::log10 (std::abs (x)); - double r = std::fmod (l, 1.); - a = std::pow (10.0, r); - b = static_cast (l-r); - if (a < 1) - { - a *= 10; - b -= 1; - } - - if (x < 0) - a = -a; - } -} - -// A translation from Tom Holoryd's python code at -// http://kurage.nimh.nih.gov/tomh/tics.py -// FIXME -- add log ticks - -void -axes::properties::calc_ticks (const array_property& lims, array_property& ticks) -{ - int ticint = 5; + + // FIXME -- add log ticks and lims if (lims.get ().is_empty ()) return; double lo = (lims.get ().matrix_value ()) (0); double hi = (lims.get ().matrix_value ()) (1); - - // Reference: Lewart, C. R., "Algorithms SCALE1, SCALE2, and - // SCALE3 for Determination of Scales on Computer Generated - // Plots", Communications of the ACM, 10 (1973), 639-640. - // Also cited as ACM Algorithm 463. - - double a; - int b, x; - - magform ((hi-lo)/ticint, a, b); - - static const double sqrt_2 = sqrt (2.0); - static const double sqrt_10 = sqrt (10.0); - static const double sqrt_50 = sqrt (50.0); - - if (a < sqrt_2) - x = 1; - else if (a < sqrt_10) - x = 2; - else if (a < sqrt_50) - x = 5; + + double tick_sep = calc_tick_sep (lo , hi); + + int i1 = static_cast (std::floor (lo / tick_sep)); + int i2 = static_cast (std::ceil (hi / tick_sep)); + + if (limmode_is_auto) + { + // adjust limits to include min and max tics + Matrix tmp_lims (1,2); + tmp_lims(0) = tick_sep * i1; + tmp_lims(1) = tick_sep * i2; + + lims = tmp_lims; + } else - x = 10; - - double sep = x * std::pow (10., b); - - // FIXME x can now be used to set minor ticks - if (x == 10) - x = 1; - - // The following guarantees that if zero is in the range, it will be - // included as a tic. - - int i1 = static_cast (std::floor (lo / sep)); - int i2 = static_cast (std::ceil (hi / sep)); - - Matrix limits (1, i2-i1+1); - for (int i = 0; i < i2-i1+1; i++) - limits (i) = sep*(i+i1); - - ticks = limits; + { + // adjust min and max tics if they are out of limits + i1 = static_cast (std::ceil (lo / tick_sep)); + i2 = static_cast (std::floor (hi / tick_sep)); + } + + Matrix tmp_ticks (1, i2-i1+1); + for (int i = 0; i <= i2-i1; i++) + tmp_ticks (i) = tick_sep * (i+i1); + + ticks = tmp_ticks; } static bool updating_axis_limits = false; @@ -2438,8 +2456,8 @@ } } - limits = get_axis_limits (min_val, max_val, min_pos, - xproperties.xscale_is ("log")); + limits = xproperties.get_axis_limits (min_val, max_val, min_pos, + xproperties.xscale_is ("log")); update_type = 'x'; } @@ -2472,8 +2490,8 @@ } } - limits = get_axis_limits (min_val, max_val, min_pos, - xproperties.yscale_is ("log")); + limits = xproperties.get_axis_limits (min_val, max_val, min_pos, + xproperties.yscale_is ("log")); update_type = 'y'; } @@ -2495,8 +2513,8 @@ } } - limits = get_axis_limits (min_val, max_val, min_pos, - xproperties.zscale_is ("log")); + limits = xproperties.get_axis_limits (min_val, max_val, min_pos, + xproperties.zscale_is ("log")); update_type = 'z'; } diff -r 68550ad9ee9c -r 3584f37eac69 src/graphics.h.in --- a/src/graphics.h.in Tue Feb 12 16:37:56 2008 +0100 +++ b/src/graphics.h.in Thu Feb 14 06:33:29 2008 +0200 @@ -2551,30 +2551,29 @@ void update_ydir (void) { update_camera (); } void update_zdir (void) { update_camera (); } - void magform (double x, double& a, int &b); - - void calc_ticks (const array_property& lims, array_property& ticks); + double calc_tick_sep (double minval, double maxval); + void calc_ticks_and_lims (array_property& lims, array_property& ticks, bool limmode_is_auto); public: + Matrix get_axis_limits (double xmin, double xmax, double min_pos, bool logscale); void update_xlim (void) { if (xtickmode.is ("auto")) - calc_ticks (xlim, xtick); + calc_ticks_and_lims (xlim, xtick, xlimmode.is ("auto")); } void update_ylim (void) { if (ytickmode.is ("auto")) - calc_ticks (ylim, ytick); + calc_ticks_and_lims (ylim, ytick, ylimmode.is ("auto")); } void update_zlim (void) { if (ztickmode.is ("auto")) - calc_ticks (zlim, ztick); + calc_ticks_and_lims (zlim, ztick, zlimmode.is ("auto")); } - }; private: