bugGNU Octave - Bugs: bug #59731, wrong colorbar length when aspect...

 
 

bug #59731: wrong colorbar length when aspect ratio is manual

Submitter:  Hg200 <hg200>
Submitted:  Sat 19 Dec 2020 04:05:33 PM UTC
   
 
Category:  Plotting Severity:  3 - Normal
Priority:  5 - Normal Item Group:  Incorrect Result
Status:  Confirmed Assigned to:  None
Originator Name:  Hg200 Open/Closed:  * Open
Release:  * 6.1.0 Operating System:  * Any
Fixed Release:  None Planned Release:  None
* Mandatory Fields

Add a New Comment Rich Markup
   

Jump to the original submission

Wed 10 Mar 2021 10:17:04 PM UTC, comment #11: 

Ah, in this patch the content of actual_axis_position.m is additionally copied to _gnuplot_draw_axes_.m to avoid regression in the gnuplot front end. Sorry for confusion ...

Hg200 <hg200>
Wed 10 Mar 2021 09:52:03 PM UTC, comment #10: 

Ok, I am attaching my latest patch on this topic plus two test cases that better illustrate the various problems (run in subdir, will generate a lot files). Unfortunately, this bug implies "either rewrite everything" or "make as few changes as possible". If I recall correctly, I went through the various colorbar scenarios that can occur (manual, auto, quite a lot ...) and checked if the changes in the attached patch were OK. The patch cleans up _actual_axis_position_.m and moves the code to colorbar.m. The downside of this approach is that _actual_axis_position_.m is unfortunately also used in the gnuplot front end. But I never figured out under which circumstances the function is called. Unfortunately I had to stop working on it, sorry.

What does the patch do now and what is the confidence?

1.) IMO it fixes the colorbar problem in the Qt frontend and solves the unit problem.
2.) The gnuplot frontend was already broken before (you may run the test scripts with gnuplot), but with the patch it is probably even more broken (i guess).

Ps.: The patch is rather old and fails because Octave source files seems now have the year "2021" instead of "2020". Anyway the test cases still look fine over here.



(file #51040, file #51041, file #51042)

Hg200 <hg200>
Tue 09 Mar 2021 04:27:44 PM UTC, comment #9: 

@Hg200: Did you ever create a patch in the end for colorbar.m when the "units" property is changed to something besides the default?

Rik <rik5>
Group administrator
Thu 31 Dec 2020 08:21:13 PM UTC, comment #8: 

I did further research on _actual_axis_position_ (). As guessed in comment #7, this function calculates the position and size of the "image of the axes after applying the aspect ratio". To understand why this is needed, one must understand how objects are plotted in the Octave opengl-renderer. In graphics.cc


void axes::properties::update_camera (void)


the view and projection matrices are composed as a function of the viewpoint, target, up vector and the bounding box. The aspect ratio of the data is taken into account in the view matrix "x_gl_mat1". In a second step, the FOV is fitted into the bounding box. In simplified terms, this is basically controlled by the projection "x_gl_mat2".

A color bar must now be scaled based on the actual visible "image of the axes" in the figure after all those transformations. Therefore it is necessary to know the position of the axes after the projection (aspect ratio, rotation). IMO, the correct way to do this would be to create an internal variable in graphics.cc that specifies the final image size after projection. Now, the code in _actual_axis_position_ () also tries to calculate what the aspect ratio does to the image. For 2D this is easy, but for 3D it is a nightmare.

The code is not only messy, but also vulnerable. For example, it generates wrong color bar lengths when the unit is set to pixels before calling colorbar. The following test code produces color bars with two different lengths:


hax = axes ();
sombrero;
view(2)
daspect ([1,1,1]);
set (hax, 'units', 'normalized');
colorbar('south');
figure;
hax = axes ();
sombrero;
view(2)
daspect ([1,1,1]);
set (hax, 'units', 'pixels');
colorbar('south');


This is due to line 54, where axis_obj.outerposition depends on the current unit setting of the axes. If the unit is "pixels", this conversion is wrong:


pos_in_pixels = axis_obj.outerposition .* fig_position([3, 4, 3, 4]);


I think, based on what we know now, I can try to create a fix for colorbar.m under the prerequisites that are mentioned in comment #7. -> colorbar length calculation is omitted in 3D / manual mode, but is taken into account for 2D plots.

Hg200 <hg200>
Mon 28 Dec 2020 03:44:55 PM UTC, comment #7: 

I have attached a file to make a colorbar investigation. It is advisable to run the file once under Octave and then with Matlab and then compare the output. Danger, many files will be generated!

Some conclusions are:

i.) In Matlab, in a view(3) plot the colorbar is almost as high as the window size. The colorbar does not seem to depend on the visible image size of the axes in the plot window. It also looks like it does not depend on whether the aspect ratio is "auto" or "manual". If we remove the "messy code" from colorbar.m (see comment #4 and comment #5) then everything becomes better in Octave. Example code:


figure ('position', [50, 100, 300, 600]);
hax = axes ();
[xx, yy] = meshgrid (linspace (-8, 8, 41));
r = sqrt ((xx).^2 + (yy).^2);
zz =  sin (r) ./ r;
surf (xx, yy, zz, 'edgecolor', 'none');
set (gcf, 'color', 'c');
view (3);
daspect ([1, 1, 1]);
hcb = colorbar ('east');


ii.) For view(2) plots in Matlab, the colorbar is scaled based on the width/height of the visible image of the axes in the plot window.  When the color bar is at the "outside" position, the length exactly matches the size of the image of the axes. Currently Octave's colorbar.m more or less honors this behavior. However, this feature breaks if we delete the "messy code" from colorbar.m. Example plot:


figure ('position', [50, 100, 600, 200]);
hax = axes ();
[xx, yy] = meshgrid (linspace (-8, 8, 41));
r = sqrt ((xx).^2 + (yy).^2);
zz =  sin (r) ./ r;
surf (xx, yy, zz, 'edgecolor', 'none');
set (gcf, 'color', 'c');
view (2);
daspect ([1, 1, 1]);
hcb = colorbar('south');


iii.) Difficulties: Currently, the Octave colobar algorithm calculates the position and length of the colorbar based on the bounding box (= hax, 'position'). The problem with this approach is that we cannot easily obtain the actual width/height of the visible axes image in the plot window, especially when we are in 3D: The actual aspect ratio of the image is determined by the opengl projection and view transformation, while the bounding box size is unaffected, even if we rotate the image. Example: The following code sequence returns the same bounding box coordinates, regardless of whether the aspect ratio is set to "manual" or "auto":


figure;
hax = axes ();
[xx, yy] = meshgrid (linspace (-8, 8, 41));
r = sqrt ((xx).^2 + (yy).^2);
zz =  sin (r) ./ r;
surf (xx, yy, zz, 'edgecolor', 'none');
set (gcf, 'color', 'c');
set (hax, "units", "pixels");
get (hax, 'position')
daspect ([1, 1, 1]);
get (hax, 'position')


References:
https://wiki.octave.org/User:Hg200

iv.) If we switch the aspect ratio in the toolkit gnuplot to "manual", then we obtain only garbage in the plot window even when there is no colorbar:


graphics_toolkit('gnuplot');
sombrero;
daspect ([1, 1, 1]);


I would vote to not maintain gnuplot any more, at least concerning this bug report.

If we want to keep feature ii.), we need some minimal corrections regarding the "aspect ratio" in "manual mode" when a view(2) plot is created. So we need to merge some of the "messy code". However, I still don't understand what exactly happens in "_actual_axis_position_.m".

Anyway, so far my evaluations.





(file #50582)

Hg200 <hg200>
Tue 22 Dec 2020 04:08:37 PM UTC, comment #6: 

I wonder if all the fiddling with placement was done to support gnuplot?

If eliminating the code produces reasonable results then we should just do that.

Rik <rik5>
Group administrator
Mon 21 Dec 2020 11:12:03 PM UTC, comment #5: 

It would be helpful to know the original purpose behind "_actual_axis_position_.m" and also the variable "off" in "calc_cbar_position". In the first part of "_actual_axis_position_.m" the position and size of the axes is determined in pixel coordinates. But then a lots of calculations follow that depend on whether the aspect ratio mode is set to "manual" or not.

I plotted the code in the OP for colorbar variants (north, west, ..., northoutside, westoutside, ...) with and without aspect ratio set to [1,1,1] in Matlab R2018. The color bar is always at the same position, regardless of whether the aspect ratio is set to "manual" or "auto". Can't we just always position the colorbar as when the aspect ratio is set to "auto"? If I remove all the code in colorbar.m that does the calculations for the manual case, and if I set the variable "off" to zero, the result doesn't look so bad. Maybe some fine tuning necessary. But probably there are cases i don't see yet ;-)

Hg200 <hg200>
Mon 21 Dec 2020 09:15:31 PM UTC, comment #4: 

More debugging shows that the root of the problem seems to be in _actual_axis_position_.m which is its own script in plot/utils.  The code in that function has a very messy exception for when the aspect ratio is "manual" and there is a FIXME note that it hasn't been tested for all cases.

Rik <rik5>
Group administrator
Mon 21 Dec 2020 05:02:03 PM UTC, comment #3: 

The colorbar created by the


colorbar ('southoutside');


command crosses out the whole image ;-) So not only the length but also the position doesn't seem to be quite right in some cases. I don't have any idea about it yet though. In this code section there are also conditions from gnuplot added. Why these strange position calculations? It would be interesting to know if that ever worked.




Hg200 <hg200>
Mon 21 Dec 2020 04:15:50 PM UTC, comment #2: 

Also confirmed that the place to resolve this is in the calc_cbar_position subfunction within colorbar.m.

Rik <rik5>
Group administrator
Mon 21 Dec 2020 05:18:19 AM UTC, comment #1: 

Confirmed.  Changing OS to Any since this also happens on Linux.

Rik <rik5>
Group administrator
Sat 19 Dec 2020 04:05:33 PM UTC, original submission:  

Run following code and compare with Matlab. I have attached also a screenshot for comparison.


hax = axes ();
[xx, yy] = meshgrid (-20:.1:20, -20:.1:20);
r = sqrt ((xx).^2 + (yy).^2);
zz =  sin (r) ./ r;
surf (xx, yy, zz, 'edgecolor', 'none');
daspect ([1, 1, 1]);
hcb = colorbar;
get (hcb, 'position')


The Matlab output for "hcb" is


0.8338    0.1100    0.0381    0.8150


I suspect the code in "calc_cbar_position" around line 600 but haven't had a closer look at this.

Hg200 <hg200>

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

Attached Files
file #51040:  patch_colorbar_v4.diff added by hg200 (11KiB - text/x-patch)
file #51041:  colorbartest_1.m added by hg200 (2KiB - text/x-objcsrc)
file #51042:  colorbartest_2.m added by hg200 (2KiB - text/x-objcsrc)
file #50582:  colbartest.m added by hg200 (2KiB - text/x-objcsrc)
file #50521:  mat_vs_oct.jpg added by hg200 (33KiB - image/jpeg)

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by rik5 (Posted a comment)
  • -email is unavailable- added by hg200 (Submitted the item)
  •  

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only group members can vote.

     

    Follow 7 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2021-03-10 hg200 Attached File- Added patch_colorbar_v4.diff, #51040
        Attached File- Added colorbartest_1.m, #51041
        Attached File- Added colorbartest_2.m, #51042
    2020-12-28 hg200 Attached File- Added colbartest.m, #50582
    2020-12-21 rik5 StatusNone Confirmed
        Operating SystemMicrosoft Windows Any
    2020-12-19 hg200 Attached File- Added mat_vs_oct.jpg, #50521

    Back to the top

    Powered by Savane 3.13-f8d8.
    Corresponding source code