Mercurial > hg > octave-nkf
diff src/graphics.cc @ 13132:e3e8ca96f923
Support log scale plots with all negative data.
Front-end fix for Bug #34232.
* src/graphics.h.in: Add "max_neg" to the array_proprerty class.
* src/graphics.cc: Determine log-scale axes ticks and limits for negative
data.
author | Ben Abbott <bpabbott@mac.com> |
---|---|
date | Mon, 12 Sep 2011 18:53:05 -0400 |
parents | d7f74a8bdc46 |
children | e81ddf9cacd5 |
line wrap: on
line diff
--- a/src/graphics.cc +++ b/src/graphics.cc @@ -657,7 +657,7 @@ template<class T> static void get_array_limits (const Array<T>& m, double& emin, double& emax, - double& eminp) + double& eminp, double& emaxp) { const T *data = m.data (); octave_idx_type n = m.numel (); @@ -677,6 +677,9 @@ if (e > 0 && e < eminp) eminp = e; + + if (e < 0 && e > emaxp) + emaxp = e; } } } @@ -1130,31 +1133,31 @@ array_property::get_data_limits (void) { xmin = xminp = octave_Inf; - xmax = -octave_Inf; + xmax = xmaxp = -octave_Inf; if (! data.is_empty ()) { if (data.is_integer_type ()) { if (data.is_int8_type ()) - get_array_limits (data.int8_array_value (), xmin, xmax, xminp); + get_array_limits (data.int8_array_value (), xmin, xmax, xminp, xmaxp); else if (data.is_uint8_type ()) - get_array_limits (data.uint8_array_value (), xmin, xmax, xminp); + get_array_limits (data.uint8_array_value (), xmin, xmax, xminp, xmaxp); else if (data.is_int16_type ()) - get_array_limits (data.int16_array_value (), xmin, xmax, xminp); + get_array_limits (data.int16_array_value (), xmin, xmax, xminp, xmaxp); else if (data.is_uint16_type ()) - get_array_limits (data.uint16_array_value (), xmin, xmax, xminp); + get_array_limits (data.uint16_array_value (), xmin, xmax, xminp, xmaxp); else if (data.is_int32_type ()) - get_array_limits (data.int32_array_value (), xmin, xmax, xminp); + get_array_limits (data.int32_array_value (), xmin, xmax, xminp, xmaxp); else if (data.is_uint32_type ()) - get_array_limits (data.uint32_array_value (), xmin, xmax, xminp); + get_array_limits (data.uint32_array_value (), xmin, xmax, xminp, xmaxp); else if (data.is_int64_type ()) - get_array_limits (data.int64_array_value (), xmin, xmax, xminp); + get_array_limits (data.int64_array_value (), xmin, xmax, xminp, xmaxp); else if (data.is_uint64_type ()) - get_array_limits (data.uint64_array_value (), xmin, xmax, xminp); + get_array_limits (data.uint64_array_value (), xmin, xmax, xminp, xmaxp); } else - get_array_limits (data.array_value (), xmin, xmax, xminp); + get_array_limits (data.array_value (), xmin, xmax, xminp, xmaxp); } } @@ -4693,7 +4696,8 @@ double minval = octave_Inf; double maxval = -octave_Inf; double min_pos = octave_Inf; - get_children_limits (minval, maxval, min_pos, kids, limit_type); + double max_neg = -octave_Inf; + get_children_limits (minval, maxval, min_pos, max_neg, kids, limit_type); if (!xisinf (minval) && !xisnan (minval) && !xisinf (maxval) && !xisnan (maxval)) { @@ -5069,7 +5073,8 @@ // FIXME -- maybe this should go into array_property class? /* static void -check_limit_vals (double& min_val, double& max_val, double& min_pos, +check_limit_vals (double& min_val, double& max_val, + double& min_pos, double& max_neg, const array_property& data) { double val = data.min_val (); @@ -5081,18 +5086,22 @@ val = data.min_pos (); if (! (xisinf (val) || xisnan (val)) && val > 0 && val < min_pos) min_pos = val; + val = data.max_neg (); + if (! (xisinf (val) || xisnan (val)) && val < 0 && val > max_neg) + max_neg = val; } */ static void -check_limit_vals (double& min_val, double& max_val, double& min_pos, +check_limit_vals (double& min_val, double& max_val, + double& min_pos, double& max_neg, const octave_value& data) { if (data.is_matrix_type ()) { Matrix m = data.matrix_value (); - if (! error_state && m.numel () == 3) + if (! error_state && m.numel () == 4) { double val; @@ -5107,6 +5116,10 @@ val = m(2); if (! (xisinf (val) || xisnan (val)) && val > 0 && val < min_pos) min_pos = val; + + val = m(3); + if (! (xisinf (val) || xisnan (val)) && val < 0 && val > max_neg) + max_neg = val; } } } @@ -5171,7 +5184,8 @@ Matrix axes::properties::get_axis_limits (double xmin, double xmax, - double min_pos, bool logscale) + double min_pos, double max_neg, + bool logscale) { Matrix retval; @@ -5182,13 +5196,17 @@ { if (logscale) { - if (xisinf (min_pos)) + if (xisinf (min_pos) && xisinf (max_neg)) { - // FIXME -- need to handle log plots with all negative data. - return default_lim (); + // TODO -- max_neg is needed for "loglog ([0 -Inf])" + // This is the only place where max_neg is needed. + // Is there another way? + retval = default_lim (); + retval(0) = pow (10., retval(0)); + retval(1) = pow (10., retval(1)); + return retval; } - - if (min_val <= 0) + if ((min_val <= 0 && max_val >= 0)) { warning ("axis: omitting nonpositive data in log plot"); min_val = min_pos; @@ -5199,8 +5217,18 @@ min_val *= 0.9; max_val *= 1.1; } - min_val = pow (10, gnulib::floor (log10 (min_val))); - max_val = pow (10, std::ceil (log10 (max_val))); + if (min_val > 0) + { + // Log plots with all positive data + min_val = pow (10, gnulib::floor (log10 (min_val))); + max_val = pow (10, std::ceil (log10 (max_val))); + } + else + { + // Log plots with all negative data + min_val = -pow (10, gnulib::floor (log10 (-min_val))); + max_val = -pow (10, std::ceil (log10 (-max_val))); + } } else { @@ -5246,19 +5274,29 @@ double lo = (lims.get ().matrix_value ()) (0); double hi = (lims.get ().matrix_value ()) (1); + bool is_negative = lo < 0 && hi < 0; + double tmp; // FIXME should this be checked for somewhere else? (i.e. set{x,y,z}lim) if (hi < lo) { - double tmp = hi; + tmp = hi; hi = lo; lo = tmp; } if (is_logscale) { - // FIXME we should check for negtives here - hi = std::log10 (hi); - lo = std::log10 (lo); + if (is_negative) + { + tmp = hi; + hi = std::log10 (-lo); + lo = std::log10 (-tmp); + } + else + { + hi = std::log10 (hi); + lo = std::log10 (lo); + } } double tick_sep = calc_tick_sep (lo , hi); @@ -5287,6 +5325,12 @@ tmp_lims(1) = std::pow (10.,tmp_lims(1)); if (tmp_lims(0) <= 0) tmp_lims(0) = std::pow (10., lo); + if (is_negative) + { + tmp = tmp_lims(0); + tmp_lims(0) = -tmp_lims(1); + tmp_lims(1) = -tmp; + } } lims = tmp_lims; } @@ -5304,6 +5348,13 @@ if (is_logscale) tmp_ticks (i) = std::pow (10., tmp_ticks (i)); } + if (is_logscale && is_negative) + { + Matrix rev_ticks (1, i2-i1+1); + rev_ticks = -tmp_ticks; + for (int i = 0; i <= i2-i1; i++) + tmp_ticks (i) = rev_ticks (i2-i1-i); + } ticks = tmp_ticks; @@ -5375,7 +5426,8 @@ } void -get_children_limits (double& min_val, double& max_val, double& min_pos, +get_children_limits (double& min_val, double& max_val, + double& min_pos, double& max_neg, const Matrix& kids, char limit_type) { octave_idx_type n = kids.numel (); @@ -5391,7 +5443,7 @@ { octave_value lim = obj.get_xlim (); - check_limit_vals (min_val, max_val, min_pos, lim); + check_limit_vals (min_val, max_val, min_pos, max_neg, lim); } } break; @@ -5405,7 +5457,7 @@ { octave_value lim = obj.get_ylim (); - check_limit_vals (min_val, max_val, min_pos, lim); + check_limit_vals (min_val, max_val, min_pos, max_neg, lim); } } break; @@ -5419,7 +5471,7 @@ { octave_value lim = obj.get_zlim (); - check_limit_vals (min_val, max_val, min_pos, lim); + check_limit_vals (min_val, max_val, min_pos, max_neg, lim); } } break; @@ -5433,7 +5485,7 @@ { octave_value lim = obj.get_clim (); - check_limit_vals (min_val, max_val, min_pos, lim); + check_limit_vals (min_val, max_val, min_pos, max_neg, lim); } } break; @@ -5447,7 +5499,7 @@ { octave_value lim = obj.get_alim (); - check_limit_vals (min_val, max_val, min_pos, lim); + check_limit_vals (min_val, max_val, min_pos, max_neg, lim); } } break; @@ -5471,6 +5523,7 @@ double min_val = octave_Inf; double max_val = -octave_Inf; double min_pos = octave_Inf; + double max_neg = -octave_Inf; char update_type = 0; @@ -5478,7 +5531,7 @@ double val; #define FIX_LIMITS \ - if (limits.numel() == 3) \ + if (limits.numel() == 4) \ { \ val = limits(0); \ if (! (xisinf (val) || xisnan (val))) \ @@ -5489,13 +5542,17 @@ val = limits(2); \ if (! (xisinf (val) || xisnan (val))) \ min_pos = val; \ + val = limits(3); \ + if (! (xisinf (val) || xisnan (val))) \ + max_neg = val; \ } \ else \ { \ - limits.resize(3, 1); \ + limits.resize(4, 1); \ limits(0) = min_val; \ limits(1) = max_val; \ limits(2) = min_pos; \ + limits(3) = max_neg; \ } if (axis_type == "xdata" || axis_type == "xscale" @@ -5507,9 +5564,10 @@ limits = xproperties.get_xlim ().matrix_value (); FIX_LIMITS ; - get_children_limits (min_val, max_val, min_pos, kids, 'x'); - - limits = xproperties.get_axis_limits (min_val, max_val, min_pos, + get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'x'); + + limits = xproperties.get_axis_limits (min_val, max_val, + min_pos, max_neg, xproperties.xscale_is ("log")); update_type = 'x'; @@ -5524,9 +5582,10 @@ limits = xproperties.get_ylim ().matrix_value (); FIX_LIMITS ; - get_children_limits (min_val, max_val, min_pos, kids, 'y'); - - limits = xproperties.get_axis_limits (min_val, max_val, min_pos, + get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'y'); + + limits = xproperties.get_axis_limits (min_val, max_val, + min_pos, max_neg, xproperties.yscale_is ("log")); update_type = 'y'; @@ -5541,9 +5600,10 @@ limits = xproperties.get_zlim ().matrix_value (); FIX_LIMITS ; - get_children_limits (min_val, max_val, min_pos, kids, 'z'); - - limits = xproperties.get_axis_limits (min_val, max_val, min_pos, + get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'z'); + + limits = xproperties.get_axis_limits (min_val, max_val, + min_pos, max_neg, xproperties.zscale_is ("log")); update_type = 'z'; @@ -5558,7 +5618,7 @@ limits = xproperties.get_clim ().matrix_value (); FIX_LIMITS ; - get_children_limits (min_val, max_val, min_pos, kids, 'c'); + get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'c'); if (min_val > max_val) { @@ -5586,7 +5646,7 @@ limits = xproperties.get_alim ().matrix_value (); FIX_LIMITS ; - get_children_limits (min_val, max_val, min_pos, kids, 'a'); + get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'a'); if (min_val > max_val) { @@ -5662,6 +5722,7 @@ double min_val = octave_Inf; double max_val = -octave_Inf; double min_pos = octave_Inf; + double max_neg = -octave_Inf; char update_type = 0; @@ -5673,9 +5734,10 @@ { if (xproperties.xlimmode_is ("auto")) { - get_children_limits (min_val, max_val, min_pos, kids, 'x'); - - limits = xproperties.get_axis_limits (min_val, max_val, min_pos, + get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'x'); + + limits = xproperties.get_axis_limits (min_val, max_val, + min_pos, max_neg, xproperties.xscale_is ("log")); update_type = 'x'; @@ -5687,9 +5749,10 @@ { if (xproperties.ylimmode_is ("auto")) { - get_children_limits (min_val, max_val, min_pos, kids, 'y'); - - limits = xproperties.get_axis_limits (min_val, max_val, min_pos, + get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'y'); + + limits = xproperties.get_axis_limits (min_val, max_val, + min_pos, max_neg, xproperties.yscale_is ("log")); update_type = 'y'; @@ -5701,9 +5764,10 @@ { if (xproperties.zlimmode_is ("auto")) { - get_children_limits (min_val, max_val, min_pos, kids, 'z'); - - limits = xproperties.get_axis_limits (min_val, max_val, min_pos, + get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'z'); + + limits = xproperties.get_axis_limits (min_val, max_val, + min_pos, max_neg, xproperties.zscale_is ("log")); update_type = 'z'; @@ -5715,7 +5779,7 @@ { if (xproperties.climmode_is ("auto")) { - get_children_limits (min_val, max_val, min_pos, kids, 'c'); + get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'c'); if (min_val > max_val) { @@ -5740,7 +5804,7 @@ { if (xproperties.alimmode_is ("auto")) { - get_children_limits (min_val, max_val, min_pos, kids, 'a'); + get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'a'); if (min_val > max_val) { @@ -5826,12 +5890,14 @@ double minx = octave_Inf; double maxx = -octave_Inf; double min_pos_x = octave_Inf; - get_children_limits (minx, maxx, min_pos_x, kids, 'x'); + double max_neg_x = -octave_Inf; + get_children_limits (minx, maxx, min_pos_x, max_neg_x, kids, 'x'); double miny = octave_Inf; double maxy = -octave_Inf; double min_pos_y = octave_Inf; - get_children_limits (miny, maxy, min_pos_y, kids, 'y'); + double max_neg_y = -octave_Inf; + get_children_limits (miny, maxy, min_pos_y, max_neg_y, kids, 'y'); // Perform the zooming xlims (0) = x + factor * (xlims (0) - x); @@ -5875,12 +5941,14 @@ double minx = octave_Inf; double maxx = -octave_Inf; double min_pos_x = octave_Inf; - get_children_limits (minx, maxx, min_pos_x, kids, 'x'); + double max_neg_x = -octave_Inf; + get_children_limits (minx, maxx, min_pos_x, max_neg_x, kids, 'x'); double miny = octave_Inf; double maxy = -octave_Inf; double min_pos_y = octave_Inf; - get_children_limits (miny, maxy, min_pos_y, kids, 'y'); + double max_neg_y = -octave_Inf; + get_children_limits (miny, maxy, min_pos_y, max_neg_y, kids, 'y'); xlims (0) += delta_x; xlims (1) += delta_x; @@ -5948,11 +6016,12 @@ Matrix line::properties::compute_xlim (void) const { - Matrix m (1, 3); + Matrix m (1, 4); m(0) = xdata.min_val (); m(1) = xdata.max_val (); m(2) = xdata.min_pos (); + m(3) = xdata.max_neg (); return m; } @@ -5960,11 +6029,12 @@ Matrix line::properties::compute_ylim (void) const { - Matrix m (1, 3); + Matrix m (1, 4); m(0) = ydata.min_val (); m(1) = ydata.max_val (); m(2) = ydata.min_pos (); + m(3) = ydata.max_neg (); return m; } @@ -6246,6 +6316,7 @@ double min_val = octave_Inf; double max_val = -octave_Inf; double min_pos = octave_Inf; + double max_neg = -octave_Inf; Matrix limits; double val; @@ -6278,7 +6349,7 @@ update_type = 'a'; } - if (limits.numel() == 3) + if (limits.numel() == 4) { val = limits(0); if (! (xisinf (val) || xisnan (val))) @@ -6289,27 +6360,33 @@ val = limits(2); if (! (xisinf (val) || xisnan (val))) min_pos = val; + val = limits(3); + if (! (xisinf (val) || xisnan (val))) + max_neg = val; } else { - limits.resize(3,1); + limits.resize(4,1); limits(0) = min_val; limits(1) = max_val; limits(2) = min_pos; - } - - get_children_limits (min_val, max_val, min_pos, kids, update_type); + limits(3) = max_neg; + } + + get_children_limits (min_val, max_val, min_pos, max_neg, kids, update_type); unwind_protect frame; frame.protect_var (updating_hggroup_limits); updating_hggroup_limits = true; - if (limits(0) != min_val || limits(1) != max_val || limits(2) != min_pos) + if (limits(0) != min_val || limits(1) != max_val + || limits(2) != min_pos || limits(3) != max_neg) { limits(0) = min_val; limits(1) = max_val; limits(2) = min_pos; + limits(3) = max_neg; switch (update_type) { @@ -6352,36 +6429,37 @@ double min_val = octave_Inf; double max_val = -octave_Inf; double min_pos = octave_Inf; + double max_neg = -octave_Inf; char update_type = 0; if (axis_type == "xlim" || axis_type == "xliminclude") { - get_children_limits (min_val, max_val, min_pos, kids, 'x'); + get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'x'); update_type = 'x'; } else if (axis_type == "ylim" || axis_type == "yliminclude") { - get_children_limits (min_val, max_val, min_pos, kids, 'y'); + get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'y'); update_type = 'y'; } else if (axis_type == "zlim" || axis_type == "zliminclude") { - get_children_limits (min_val, max_val, min_pos, kids, 'z'); + get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'z'); update_type = 'z'; } else if (axis_type == "clim" || axis_type == "climinclude") { - get_children_limits (min_val, max_val, min_pos, kids, 'c'); + get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'c'); update_type = 'c'; } else if (axis_type == "alim" || axis_type == "aliminclude") { - get_children_limits (min_val, max_val, min_pos, kids, 'a'); + get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'a'); update_type = 'a'; } @@ -6391,11 +6469,12 @@ updating_hggroup_limits = true; - Matrix limits (1, 3, 0.0); + Matrix limits (1, 4, 0.0); limits(0) = min_val; limits(1) = max_val; limits(2) = min_pos; + limits(3) = max_neg; switch (update_type) {