Colormap utility - two axes in colorbar

Hi everyone,
I have a query regarding the colormap utility and plotting two variables using one colormap and one colorbar, the latter of which would have two axes for each variable. To accompany the more detailed query description below, please see the image attached.
I have two variables that are related to eachother (let's say A and B) where A = xB where 'x' is a unitless constant value (let's say it's 2.98 for every case). Therefore, A and B have the same units.
I would like to use a single colormap for both variables since 'x' is the variable that couples between one and the other. Now, where the right tick axis says B = 6, the left tick axis would have A equal to 17.88 which doesn't look good as a tick value. Instead I would like it to have ticks at location 18, which would have to be slightly higher up in the colorbar than 6 (see image attached). Same for the other values.
The image attached shows what I would like to code. Is this possible?
Thank you.

 Accepted Answer

dpb
dpb on 12 Aug 2019
Edited: dpb on 12 Aug 2019
Yeah, it's doable...refinements needed, but general idea works.
Z = peaks(20);
[~,hCF]=contourf(Z,10);
hAx=gca; % save axes handle main axes
hCB=colorbar; % add colorbar, save its handle
hNuCBAx=axes('Position',hCB.Position,'color','none'); % add mew axes at same posn
hNuCBAx.XAxis.Visible='off'; % hide the x axis of new
posn=hAx.Position; % get main axes location
posn(3)=0.8*posn(3); % cut down width
hAx.Position=posn; % resize mmain axes to make room for labels colorbar
hCB.Position=hNuCBAx.Position; % put the colorbar back to overlay second axeix
hNuCBAx.YLim=[-22 22]; % alternate scale limits new axis
ylabel(hCB, 'A','Rotation',0,'FontWeight','bold','VerticalAlignment','middle')
ylabel(hNuCBAx,'B','Rotation',0,'FontWeight','bold','VerticalAlignment','middle')
hCB.Position=hNuCBAx.Position; % put the colorbar back to overlay second axeix
results in
I overshot the width reduction a little and it's kinda' kludgy to have to move the original colorbar back to its original position when change the other axis size but there's an internal callback function that ties them together...

9 Comments

Jack M
Jack M on 12 Aug 2019
Edited: Jack M on 12 Aug 2019
Thanks for the prompt reply!
Tried running the code and an error came up: Undefined variable "hAx" or class "hAx.Position". I'm using Matlab 2018b - do I need to upgrade to 2019a?
Oh...I had copied the commandhistory of the playing-around session to get to the result and inadvertently deleted an extra line that needed...save the main axes handle when create the plot--fixed Answer to include it again.
Jack M
Jack M on 12 Aug 2019
Edited: Jack M on 12 Aug 2019
Thanks - the code is now complaining about the yLim property? Unrecognized property 'Ylim' for class 'matlab.graphics.axis.Axes'
Does it run fine for you?
With the fixup that the "dot" syntax for property names are case-sensitive. It's 'YLim', not 'Ylim'. Deleted the wrong line and hard to see the difference.
Also I discover that needed to move the positioning command to the end--the labels also trigger the callback on position it seems.
The above now does create the sample figure in a new figure window.
Thanks - I finally get something very close to what you got before, but still with some issues unfortunately! Probably because of my startup.m file, but unsure.
1) the axes on the right don't seem to accept me wanting the interpreter to be 'latex' even though I have added (,'Interpreter','latex')
2) The minor ticks from the left colorbar axis have gone onto the right colorbar axis too. How can one fix this? Can we have separate minor axis on each side? Just as an option, how would one turn off the minor axes on each side independently?
3) Also, for some reason there are lines inside the colorbar? Can these be removed?
Thanks a lot in advance for all your time!
result1.png
dpb
dpb on 12 Aug 2019
Edited: dpb on 12 Aug 2019
Would help to see the actual code you used for your case but...
Two of the three axes are just axes objects; in my example hAx is the main figure axis so you can set its properties with its handle; the colorbar handle points to a colorbar object but it is just an encapsulated axis object underneath--altho TMW didn't expose all of them, most are. You can see what is exposed by typing hCB at the command line and then clicking on the link to the remaining properties. The 'LabelInterpreter' is not visible unfortunately, only the tick label.
The X/YLabel for an axes is a text() object but there are functions that are available to set the label that allow you to set the appropriate internal properties hiding the actual object itself given the axes handle (or gca if not specified). The .Label property of the colorbar returns the handle of the text object for the label so it is possible to get to it, however:
hCB.Label.Interpreter='latex';
hCB.Label.Rotation=0;
hCB.Label.String='$$\sum$$';
displays the capital sigma on the RH side.
hNuCBAx is the new axes added, it doesn't have anything hidden so you can modify any of its properties like any other ordinary axis...
hNuCBAx.YMinorTick='off';
The above using ylabel for hCB I see ends up occluding the LH axes label already written if called a susequent time; I suppose problem brought it to the foreground by doing so. Setting the properties is probably what need to do for such special effects altho is more work.
Consult properties link under the documentation for axes to see all that can be addressed.
ADDENDUM:
Interesting thought -- there is a hidden property under the colorbar handle hCB of .Axes that is the handle of the axes object that can then see everything for an ordinary axes through. Wonder if you were to create the colorbar as normal, then retrieve that (hidden) handle if you could then use the newfangle yyaxis left/right command to create a secondary RH axis and have a little more user-friendly way to address it?
ADDENDUM SECOND:
Well, that doesn't seem to work as one would hope...
hCBAxes=hCB.Axes; % return the underlying axes object
turns out is the axes of the main plot, NOT that from which the colorbar object was built on top of. That is, afaict, not retrievable so the above idea doesn't pan out, unfortunately.
Well, rereading the documentation enough times I realize that I've had a misconception--an axes CAN have more than one colorbar object...just that if the second is tried to be created on top of the first the first is silently deleted. Testing shows this is so even if try to trick HG2 by using the 'Position' property instead of one of the named locations--it checks internally and still wipes out the first.
Thus, you can create one on the east and another on the west and then move the west one to the position read from the east but the axes size callbacks and internal logic moves the main axes width and the two don't end up overlaying each other exactly...so, while it's easy way to create two objects of the same kind on the figure, it appears to be at least as much if not more trouble to actually create the desired effect as compared to the first try above...as with yyaxis there's just too much going on behind the scenes don't have control over.
Jack M
Jack M on 13 Aug 2019
Edited: Jack M on 13 Aug 2019
Thanks for this - I really appreciate your help and in depth description. I will give these a go and get back to you in a few days to confirm the answer works!
dpb
dpb on 14 Aug 2019
Edited: dpb on 14 Aug 2019
Good luck!
Just thought of another potential "gotcha'!" The new axis does not have any link to the colorbar so if you make modifications to the plot that trigger the colorbar callbacks on position, the overlap is probably going to break and the position would need to be reset for hNuCBAx. I've not tried to think through what it would take to write the suitable callback for it...unfortunately, since one can't find the handle to an axis for the colorbar even with Yair's undocumented function to find hidden properties, there's no way to use linkaxes.
The ability to have the colorbar property .AxisLocation be 'both' as well as either 'in' or 'out' could be a worthwhile enhancement request. With that (and the subsequent changing of the properties to be able to address both instead of just one), this would be a trivial exercise. And, if that were done when the object was created via something like yyaxis() on the target area before being encapsulated, then the effort to do it at that level wouldn't seem to be that much of a stretch...
Whether TMW would think the usage of high enough frequency to make the list is debatable, but if one never suggests... :)

Sign in to comment.

More Answers (1)

Thank you dpb. The connection between 2 axes are achieved using updated version of your code.
https://in.mathworks.com/matlabcentral/fileexchange/79295-multiple-axes-colorbar

Categories

Find more on Creating, Deleting, and Querying Graphics Objects in Help Center and File Exchange

Asked:

on 11 Aug 2019

Edited:

on 12 Jun 2021

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!