changeset 29071:d2f7fb06bce3

Fixed stacked bar chart handling of negative values (bug #58216) * NEWS: Added note about bar and barh matching Matlab output to Matlab compatibility section. * __bar__.m: Updated input parsing to separately handle negative stacked values. * bar.m, barh.m: Added demo and input error handling BISTS. * * * (bug #58216)
author Nicholas R. Jankowski <jankowskin@asme.org>
date Tue, 17 Nov 2020 15:52:03 -0500
parents ab3e0676b8d6
children a0be96cd13c5
files NEWS scripts/plot/draw/bar.m scripts/plot/draw/barh.m scripts/plot/draw/private/__bar__.m
diffstat 4 files changed, 54 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Wed Nov 18 19:45:04 2020 -0800
+++ b/NEWS	Tue Nov 17 15:52:03 2020 -0500
@@ -155,6 +155,12 @@
 Matlab code, but for which Octave does not yet implement the
 functionality.  By default, this warning is enabled.
 
+- The functions `bar` and `barh` now handle stacked negative bar values
+in a Matlab-compatible manner.  Negative values now stack below the zero
+axis independently of a positive value bars in the same stack.
+Previously the negative bars could overlap positive bars depending on
+drawing order.
+
 ### Alphabetical list of new functions added in Octave 7
 
 * `getpixelposition`
--- a/scripts/plot/draw/bar.m	Wed Nov 18 19:45:04 2020 -0800
+++ b/scripts/plot/draw/bar.m	Tue Nov 17 15:52:03 2020 -0500
@@ -124,7 +124,6 @@
   [varargout{:}] = __bar__ (true, "bar", varargin{:});
 endfunction
 
-
 %!demo
 %! clf;
 %! y = rand (11, 1);
@@ -144,3 +143,17 @@
 %! clf;
 %! h = bar (rand (5, 3), "stacked");
 %! title ("bar() graph with stacked style");
+
+%!demo
+%! clf;
+%! y = -rand (3) .* eye (3) + rand (3) .* (! eye (3));
+%! h = bar (y, "stacked");
+%! title ("stacked bar() graph including intermingled negative values");
+
+%% Test input validation
+%!error bar ()
+%!error <Y must be numeric> bar ("foo")
+%!error <X must be a vector> bar ([1 2; 3 4], [1 2 3 4])
+%!error <X vector values must be unique> bar ([1 2 3 3], [1 2 3 4])
+%!error <length of X and Y must be equal> bar ([1 2 3], [1 2 3 4])
+%!error <length of X and Y must be equal> bar ([1 2 3 4], [1 2 3])
--- a/scripts/plot/draw/barh.m	Wed Nov 18 19:45:04 2020 -0800
+++ b/scripts/plot/draw/barh.m	Tue Nov 17 15:52:03 2020 -0500
@@ -95,3 +95,17 @@
 %! set (h(2), "facecolor", "g");
 %! set (h(3), "facecolor", "b");
 %! title ("barh() graph w/multiple bars");
+
+%!demo
+%! clf;
+%! x = -rand (3) .* eye (3) + rand (3) .* (! eye (3));
+%! h = barh (x, "stacked");
+%! title ("stacked barh() graph including intermingled negative values");
+
+%% Test input validation
+%!error barh ()
+%!error <Y must be numeric> barh ("foo")
+%!error <X must be a vector> barh ([1 2; 3 4], [1 2 3 4])
+%!error <X vector values must be unique> barh ([1 2 3 3], [1 2 3 4])
+%!error <length of X and Y must be equal> barh ([1 2 3], [1 2 3 4])
+%!error <length of X and Y must be equal> barh ([1 2 3 4], [1 2 3])
--- a/scripts/plot/draw/private/__bar__.m	Wed Nov 18 19:45:04 2020 -0800
+++ b/scripts/plot/draw/private/__bar__.m	Tue Nov 17 15:52:03 2020 -0500
@@ -38,6 +38,7 @@
 
   width = 0.8;
   group = true;
+  stacked = false;
   histc = NA;
   ## BaseValue
   if (strcmp (get (hax, "yscale"), "log"))
@@ -84,6 +85,7 @@
       group = true;
       idx += 1;
     elseif (ischar (varargin{idx}) && strcmpi (varargin{idx}, "stacked"))
+      stacked = true;
       group = false;
       idx += 1;
     elseif (ischar (varargin{idx}) && strcmpi (varargin{idx}, "histc"))
@@ -185,8 +187,24 @@
     y0 = zeros (size (y)) + bv;
     y1 = y;
   else
-    y1 = cumsum (y,2);
-    y0 = [zeros(ngrp,1)+bv, y1(:,1:end-1)];
+    if (stacked && any (y(:) < 0))
+      ypos = (y >= 0);
+      yneg = (y <  0);
+      ypos = y .* ypos;
+      yneg = y .* yneg;
+
+      y1p =  cumsum (y .* ypos, 2);
+      y1n =  cumsum (y .* yneg, 2);
+      y1 = y1p .* ypos + y1n .* yneg;
+
+      y0p = [zeros(ngrp,1)+bv, y1p(:,1:end-1)];
+      y0n = [zeros(ngrp,1)+bv, y1n(:,1:end-1)];
+      y0 = y0p .* ypos + y0n .* yneg;
+
+    else
+      y1 = cumsum (y,2);
+      y0 = [zeros(ngrp,1)+bv, y1(:,1:end-1)];
+    endif
   endif
 
   yb = zeros (4*ngrp, nbars);