# HG changeset patch
# User Nicholas R. Jankowski <jankowskin@asme.org>
# Date 1605646323 18000
#      Tue Nov 17 15:52:03 2020 -0500
# Node ID 5b4d16917632695324f72d03a141767326160994
# Parent  d8089b13d4d7fd4b8e79115bd40388cbb0720692
Fixed stacked bar chart handling of negative values (bug #58216)
* /scripts/plot/draw/private/__bar__.m: updated input parsing to separately handle negative stacked values
* /scripts/plot/draw/bar.m: added demo and input error handling BISTS
* /scripts/plot/draw/barh.m: added demo and input error handling BISTS
* /NEWS: added note about bar & barh matching Matlab output to Matlab compatibility section

diff -r d8089b13d4d7 -r 5b4d16917632 NEWS
--- a/NEWS	Sun Nov 15 21:52:58 2020 +0100
+++ b/NEWS	Tue Nov 17 15:52:03 2020 -0500
@@ -155,6 +155,11 @@
 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`
diff -r d8089b13d4d7 -r 5b4d16917632 scripts/plot/draw/bar.m
--- a/scripts/plot/draw/bar.m	Sun Nov 15 21:52:58 2020 +0100
+++ 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 <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])
+%!error <X vector values must be unique> bar ([1 2 3 3], [1 2 3 4])
+%!error <X must be a vector> bar ([1 2; 3 4], [1 2 3 4])
diff -r d8089b13d4d7 -r 5b4d16917632 scripts/plot/draw/barh.m
--- a/scripts/plot/draw/barh.m	Sun Nov 15 21:52:58 2020 +0100
+++ 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 <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])
+%!error <X vector values must be unique> barh ([1 2 3 3], [1 2 3 4])
+%!error <X must be a vector> barh ([1 2; 3 4], [1 2 3 4])
diff -r d8089b13d4d7 -r 5b4d16917632 scripts/plot/draw/private/__bar__.m
--- a/scripts/plot/draw/private/__bar__.m	Sun Nov 15 21:52:58 2020 +0100
+++ 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,22 @@
     y0 = zeros (size (y)) + bv;
     y1 = y;
   else
-    y1 = cumsum (y,2);
-    y0 = [zeros(ngrp,1)+bv, y1(:,1:end-1)];
+    if (stacked & (any (any (y < 0))))
+      ypos = y .* (y >= 0);
+      yneg = y .* (y < 0);
+
+      y1p =  cumsum (ypos, 2);
+      y1n =  cumsum (yneg, 2);
+      y1 = y1p .* (y >= 0) + y1n .* (y < 0);
+
+      y0p = [zeros(ngrp,1)+bv, y1p(:,1:end-1)];
+      y0n = [zeros(ngrp,1)+bv, y1n(:,1:end-1)];
+      y0 = y0p .* (y >= 0) + y0n .* (y < 0);
+
+    else
+      y1 = cumsum (y,2);
+      y0 = [zeros(ngrp,1)+bv, y1(:,1:end-1)];
+    endif
   endif
 
   yb = zeros (4*ngrp, nbars);
