# HG changeset patch
# User Markus Meisinger <chloros2@gmx.de>
# Date 1610312165 -3600
#      Sun Jan 10 21:56:05 2021 +0100
# Node ID 8301558b44be99e6ed2d7b19998894f667b15b6e
# Parent  7bfc454b9e0849ebc1d4515c2ff79a68b876d06a
Fix colorbar length when aspect ratio is manual (bug #59731).

* colorbar.m:
* 3D-plot colorbars are always scaled based on the axes auto position.
* 2D-plot colorbars in manual mode are scaled to the image of the axes.
* The units of the plot axes are correctly taken into account.
* module.mk: remove __actual_axis_position__.m
* __gnuplot_draw_axes__.m: move code from __actual_axis_position__.m


diff -r 7bfc454b9e08 -r 8301558b44be scripts/plot/draw/colorbar.m
--- a/scripts/plot/draw/colorbar.m	Thu Jan 07 11:11:39 2021 -0800
+++ b/scripts/plot/draw/colorbar.m	Sun Jan 10 21:56:05 2021 +0100
@@ -519,12 +519,18 @@
 ## FIXME: Should handle user-specified "AxisLocation" property (mirror var).
 function [axpos, cbpos, vertical, mirr] = calc_cbar_position (loc, props, cf)
 
+  nd = __calc_dimensions__ (props.__axes_handle__);
+
   ## This will always represent the position prior to adding the colorbar.
   axpos = props.position;
   sz = axpos(3:4);
 
-  if (strcmp (props.plotboxaspectratiomode, "manual")
+  ## 2D-plot colorbars in manual mode are scaled based on the image of
+  ## the axes after applying the aspect ratio. 3D-plot colorbars are scaled
+  ## based on the auto width / height of the axes position.
+  if ((strcmp (props.plotboxaspectratiomode, "manual")
       || strcmp (props.dataaspectratiomode, "manual"))
+      && (nd == 2 || all (mod (props.view, 90) == 0)))
     if (isempty (strfind (loc, "outside")))
       scale = 1.0;
     else
@@ -535,14 +541,8 @@
     else
       scale = [scale, 1];
     endif
-    if (strcmp (get (cf, "__graphics_toolkit__"), "gnuplot")
-        && strcmp (props.positionconstraint, "outerposition"))
-      props.outerposition = props.outerposition .* [1, 1, scale];
-      off = 0.5 * (props.outerposition (3:4) - __actual_axis_position__ (props)(3:4));
-    else
-      props.position = props.position .* [1, 1, scale];
-      off = 0.5 * (props.position (3:4) - __actual_axis_position__ (props)(3:4));
-    endif
+    props.position = props.position .* [1, 1, scale];
+    off = 0.5 * (props.position (3:4) - actual_2d_axis_position (props)(3:4));
   else
     off = 0.0;
   endif
@@ -598,10 +598,12 @@
 
   cbpos = [origin, sz];
 
-  if (strcmp (props.plotboxaspectratiomode, "manual")
+  if ((strcmp (props.plotboxaspectratiomode, "manual")
       || strcmp (props.dataaspectratiomode, "manual"))
+      && (nd == 2 || all (mod (props.view, 90) == 0)))
     props.position = axpos;
-    actual_pos = __actual_axis_position__ (props);
+    actual_pos = actual_2d_axis_position (props);
+    ## Colorbar length in multiples of the axes
     if (strfind (loc, "outside"))
       scale = 1.0;
     else
@@ -622,6 +624,40 @@
 
 endfunction
 
+## Image of 2D-plot axes after aspect ratio is applied.
+function actual_pos = actual_2d_axis_position (axis_obj)
+
+  ## Convert ax position to "pixels" if the unit is "normalized"
+  if (strcmp (axis_obj.units, "normalized"))
+    fig_pos = getpixelposition (axis_obj.parent);
+    orig_pos = axis_obj.position .* fig_pos([3, 4, 3, 4]);
+  else
+    orig_pos = axis_obj.position;
+  endif
+
+  ## Calculate position of the image. Works for "pixel", "points" etc. but
+  ## not for "normalized"
+  scale = axis_obj.plotboxaspectratio(1:2) ./ orig_pos(3:4);
+  scale = scale ./ max (scale);
+  if (scale(1) < scale(2))
+    dx = (1.0 - scale(1)) * orig_pos(3);
+    scaled_pos = orig_pos + dx * [0.5, 0.0, -1.0, 0.0];
+  elseif (scale(1) > scale(2))
+    dy = (1.0 - scale(2)) * orig_pos(4);
+    scaled_pos = orig_pos + dy * [0.0, 0.5, 0.0, -1.0];
+  else
+    scaled_pos = orig_pos;
+  endif
+
+  ## Convert back to "normalized" if necessary
+  if strcmp (axis_obj.units, "normalized")
+    actual_pos = scaled_pos ./ fig_pos([3, 4, 3, 4]);
+  else
+    actual_pos = scaled_pos;
+  endif
+
+endfunction
+
 
 %!demo
 %! clf;
diff -r 7bfc454b9e08 -r 8301558b44be scripts/plot/util/__actual_axis_position__.m
--- a/scripts/plot/util/__actual_axis_position__.m	Thu Jan 07 11:11:39 2021 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-########################################################################
-##
-## Copyright (C) 2009-2020 The Octave Project Developers
-##
-## See the file COPYRIGHT.md in the top-level directory of this
-## distribution or <https://octave.org/copyright/>.
-##
-## This file is part of Octave.
-##
-## Octave is free software: you can redistribute it and/or modify it
-## under the terms of the GNU General Public License as published by
-## the Free Software Foundation, either version 3 of the License, or
-## (at your option) any later version.
-##
-## Octave is distributed in the hope that it will be useful, but
-## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with Octave; see the file COPYING.  If not, see
-## <https://www.gnu.org/licenses/>.
-##
-########################################################################
-
-## -*- texinfo -*-
-## @deftypefn  {} {} __actual_axis_position__ (@var{h})
-## @deftypefnx {} {} __actual_axis_position__ (@var{axis_struct})
-## Undocumented internal function.
-## @end deftypefn
-
-function pos = __actual_axis_position__ (h)
-
-  if (ishghandle (h))
-    axis_obj = get (h);
-  elseif (isstruct (h))
-    axis_obj = h;
-    h = axis_obj.__axes_handle__;
-  endif
-
-  ## Get figure size in pixels
-  orig_fig_units = get (axis_obj.parent, "units");
-  orig_fig_position = get (axis_obj.parent, "position");
-  unwind_protect
-    set (axis_obj.parent, "units", "pixels");
-    fig_position = get (axis_obj.parent, "position");
-  unwind_protect_cleanup
-    set (axis_obj.parent, "units", orig_fig_units,
-                          "position", orig_fig_position);
-  end_unwind_protect
-  ## Get axes size in pixels
-  if (strcmp (get (axis_obj.parent, "__graphics_toolkit__"), "gnuplot")
-      && strcmp (axis_obj.positionconstraint, "outerposition"))
-    pos_in_pixels = axis_obj.outerposition .* fig_position([3, 4, 3, 4]);
-  else
-    pos_in_pixels = axis_obj.position .* fig_position([3, 4, 3, 4]);
-  endif
-
-  nd = __calc_dimensions__ (h);
-
-  if (strcmp (axis_obj.plotboxaspectratiomode, "manual")
-      || strcmp (axis_obj.dataaspectratiomode, "manual"))
-    ## When using {rltb}margin, Gnuplot does not handle the specified
-    ## aspect ratio properly, so handle it here.
-    if (nd == 2 || all (mod (axis_obj.view, 90) == 0))
-      aspect_ratio_2d = axis_obj.plotboxaspectratio(1:2);
-    else
-      ## FIXME: This works for "axis square", but has not been
-      ##        thoroughly tested for other aspect ratios.
-      aspect_ratio_2d = [max(axis_obj.plotboxaspectratio(1:2)), ...
-                             axis_obj.plotboxaspectratio(3)/sqrt(2)];
-    endif
-    orig_aspect_ratio_2d = pos_in_pixels(3:4);
-    rel_aspect_ratio_2d = aspect_ratio_2d ./ orig_aspect_ratio_2d;
-    rel_aspect_ratio_2d ./= max (rel_aspect_ratio_2d);
-    if (rel_aspect_ratio_2d(1) < rel_aspect_ratio_2d(2))
-      dx = (1.0 - rel_aspect_ratio_2d(1)) * pos_in_pixels(3);
-      pos_in_pixels += dx*[0.5, 0.0, -1.0, 0.0];
-    elseif (rel_aspect_ratio_2d(1) > rel_aspect_ratio_2d(2))
-      dy = (1.0 - rel_aspect_ratio_2d(2)) * pos_in_pixels(4);
-      pos_in_pixels += dy*[0.0, 0.5, 0.0, -1.0];
-    endif
-    pos = pos_in_pixels ./ fig_position([3, 4, 3, 4]);
-  elseif (strcmp (get (axis_obj.parent, "__graphics_toolkit__"), "gnuplot")
-          && strcmp (axis_obj.positionconstraint, "outerposition"))
-    pos = axis_obj.outerposition;
-  else
-    pos = axis_obj.position;
-  endif
-
-endfunction
-
-
-## No test coverage for internal function.  It is tested through calling fcn.
-%!assert (1)
diff -r 7bfc454b9e08 -r 8301558b44be scripts/plot/util/module.mk
--- a/scripts/plot/util/module.mk	Thu Jan 07 11:11:39 2021 -0800
+++ b/scripts/plot/util/module.mk	Sun Jan 10 21:56:05 2021 +0100
@@ -25,7 +25,6 @@
 
 %canon_reldir%_FCN_FILES = \
   %reldir%/.oct-config \
-  %reldir%/__actual_axis_position__.m \
   %reldir%/__default_plot_options__.m \
   %reldir%/__gnuplot_drawnow__.m \
   %reldir%/__next_line_color__.m \
diff -r 7bfc454b9e08 -r 8301558b44be scripts/plot/util/private/__gnuplot_draw_axes__.m
--- a/scripts/plot/util/private/__gnuplot_draw_axes__.m	Thu Jan 07 11:11:39 2021 -0800
+++ b/scripts/plot/util/private/__gnuplot_draw_axes__.m	Sun Jan 10 21:56:05 2021 +0100
@@ -77,7 +77,7 @@
     apos = axis_obj.position;
   endif
 
-  pos = __actual_axis_position__ (h);
+  pos = actual_axis_position (h);
 
   if (strcmp (axis_obj.dataaspectratiomode, "manual"))
     dr = axis_obj.dataaspectratio;
@@ -2890,3 +2890,64 @@
   endif
 
 endfunction
+
+function pos = actual_axis_position (h)
+
+  if (ishghandle (h))
+    axis_obj = get (h);
+  elseif (isstruct (h))
+    axis_obj = h;
+    h = axis_obj.__axes_handle__;
+  endif
+
+  ## Get figure size in pixels
+  orig_fig_units = get (axis_obj.parent, "units");
+  orig_fig_position = get (axis_obj.parent, "position");
+  unwind_protect
+    set (axis_obj.parent, "units", "pixels");
+    fig_position = get (axis_obj.parent, "position");
+  unwind_protect_cleanup
+    set (axis_obj.parent, "units", orig_fig_units,
+                          "position", orig_fig_position);
+  end_unwind_protect
+  ## Get axes size in pixels
+  if (strcmp (get (axis_obj.parent, "__graphics_toolkit__"), "gnuplot")
+      && strcmp (axis_obj.positionconstraint, "outerposition"))
+    pos_in_pixels = axis_obj.outerposition .* fig_position([3, 4, 3, 4]);
+  else
+    pos_in_pixels = axis_obj.position .* fig_position([3, 4, 3, 4]);
+  endif
+
+  nd = __calc_dimensions__ (h);
+
+  if (strcmp (axis_obj.plotboxaspectratiomode, "manual")
+      || strcmp (axis_obj.dataaspectratiomode, "manual"))
+    ## When using {rltb}margin, Gnuplot does not handle the specified
+    ## aspect ratio properly, so handle it here.
+    if (nd == 2 || all (mod (axis_obj.view, 90) == 0))
+      aspect_ratio_2d = axis_obj.plotboxaspectratio(1:2);
+    else
+      ## FIXME: This works for "axis square", but has not been
+      ##        thoroughly tested for other aspect ratios.
+      aspect_ratio_2d = [max(axis_obj.plotboxaspectratio(1:2)), ...
+                             axis_obj.plotboxaspectratio(3)/sqrt(2)];
+    endif
+    orig_aspect_ratio_2d = pos_in_pixels(3:4);
+    rel_aspect_ratio_2d = aspect_ratio_2d ./ orig_aspect_ratio_2d;
+    rel_aspect_ratio_2d ./= max (rel_aspect_ratio_2d);
+    if (rel_aspect_ratio_2d(1) < rel_aspect_ratio_2d(2))
+      dx = (1.0 - rel_aspect_ratio_2d(1)) * pos_in_pixels(3);
+      pos_in_pixels += dx*[0.5, 0.0, -1.0, 0.0];
+    elseif (rel_aspect_ratio_2d(1) > rel_aspect_ratio_2d(2))
+      dy = (1.0 - rel_aspect_ratio_2d(2)) * pos_in_pixels(4);
+      pos_in_pixels += dy*[0.0, 0.5, 0.0, -1.0];
+    endif
+    pos = pos_in_pixels ./ fig_position([3, 4, 3, 4]);
+  elseif (strcmp (get (axis_obj.parent, "__graphics_toolkit__"), "gnuplot")
+          && strcmp (axis_obj.positionconstraint, "outerposition"))
+    pos = axis_obj.outerposition;
+  else
+    pos = axis_obj.position;
+  endif
+
+endfunction
