Matlab: How to assign different colormaps/colorbars to different surfaces in the same Figure
Asked Answered
N

3

12

I am fairly new to Matlab and have a few questions. I got two surfaces and a plane in the same figure. I want to use different colormap and colorbar for b and another colormap and colorbar for c. s is fixed color so it's not a problem.

Let me try to explain what I am trying to achieve:

cmap1=colormap(topobathy) -->cmap1 is 64x3 double as expected

cmap2=colormap(redwhitegreen)

create cdata1 using cmap1 (this is the first part I cannot figure out, how to scale z data using cmap1, by default CData contains the z values)

b=surf(x,y,z,cdata1)

colorbar for b using z values

c=pcolor(x,y,(z-z0)) - I want to use cmap2 for this one.

colorbar for c using (z-z0) values

Here is what I have so far and the problems I encounter

b=surf(x,y,z);
colormap(topobathy);
cbar1=colorbar;
set(get(cbar1,'ylabel'),'String', 'Elevation (m)', 'Rotation', 90)
hold on;
s=surf(x,y,z1,'FaceColor',[0.278 0.788 0.788])
hold on;
change=z-z0;     
c=pcolor(x,y,change)
set(c,'ZData',100 + 0*change); %plotting it above the other surfaces
colormap(redwhitegreen)`

at this point colormap is set to redwhitegreen for b, colorbar of b I can't get the second colorbar with its own clim etc.

I used the freezeColors and cbfreeze explained in this link: http://blogs.mathworks.com/pick/2009/07/24/using-multiple-colormaps-in-a-single-figure/

but one thing works while messing another thing (probably all my fault). I want to learn how to have complete control over my objects without using external m files anyway.

Any help is appreciated.

Nedanedda answered 9/11, 2011 at 23:19 Comment(0)
U
18

The basic idea is that you concatenate the colormaps, and then shift/scale the color data (CData) of the different plot handles to line up with the desired portions of the colormap. So, without knowing what your custom functions or specific data are, you could do something like colormap(topobathy(64); redwhitegreen(64)) and then scale the CData of b into the range [1,64] and the CData of c into the range [65,128].

There is an excellent guide on the MathWorks website that explains all this (even uses surf() and pcolor() like your example):

http://www.mathworks.com/support/tech-notes/1200/1215.html#Example_1

For the colorbar, you can just fake out the ticks and labels in a similar manner. Here is rough shot at making a color bar for the above example:

h = colorbar;
ticks = [1 16:16:64 64:16:128];
ticks(5:6) = [62 66];
set(h, 'YTick', ticks);

labels = num2str(repmat(linspace(min(Z(:)), max(Z(:)), 5), 1, 2)', 2);
set(h, 'YTickLabel', labels)

enter image description here

Ul answered 10/11, 2011 at 6:34 Comment(3)
thank you for the response - that's a good link, I was aware of it but that does not apply to my problem - my surf and pcolor are using different Z datasets. I want their corresponding colorbar and colormap to reflect that.Nedanedda
There is no requirement that they be the same Z values, and I encourage you to work through that example closely. The main point is simply that each CData must be scaled/shifted onto its corresponding part of the concatenated color map. Even your color maps don't have to be 64-64, although having them the same size is always more convenient for me.Ul
@Nedanedda Further, if you really want 2 color bars, that is simple too. Just make 2 of them and then adjust the Position property so they don't overlap, and the YLim property so each only shows one part of the color map.Ul
S
1

I had the same problem as you, and the best (and only) solution I found was the next:

  1. Concatenate both colormaps I wanted:

    cmap1 = jet(64); cmap2 = copper(64); color_map = [cmap1 ; cmap2];

    So, the first colormap (cmap1) will be used for Axes1, and the second colormap (cmap2) for Axes2. I guess that Axes1 and Axes2 are in the same figure.

  2. Normalize data, giving a scale from 0 to 1 for data of Axes1, and from 1 to 2 for data of Axes2. So, Axes1 in [0, 1] and Axes2 in [1 2].

    data1 = data1 - lower_limit1; data1 = double(data1./(upper_limit1 - lower_limit1));

    For data set of Axes 2:

    data2 = data2 - lower_limit;
    data2 = double(data2./(upper_limit2 - lower_limit2)) + 1;
    
  3. When representing them:

    • Axes1:
    pcolor(handle_axes1, x_axis, y_axis, data1); shading(handle_axes1,'FLAT'); 
    caxis(handle_axes1, [0 2]);
    
    % Colorbar
    h_colorbar = colorbar('peer', handle_axes1);
    set(h_colorbar, 'YLim', [0 1]);
    
    labels = num2str(linspace(lower_limit1, upper_limit1, 6)', 2);
    set(h_colorbar, 'YTick', linspace(0, 1, 6));
    set(h_colorbar, 'YTickLabel', labels);
    
    • Axes2:
    pcolor(handle_axes2, x_axis, y_axis, data2); shading(handle_axes2,'FLAT'); 
    caxis(handle_axes2, [0 2]);
    
    % Colorbar
    h_colorbar2 = colorbar('peer', handle_axes2);
    set(h_colorbar2, 'YLim', [1 2]);
    
    labels = num2str(linspace(lower_limit2, upper_limit2, 6)', 2);
    set(h_colorbar2, 'YTick', linspace(1, 2, 6));
    set(h_colorbar2, 'YTickLabel', labels);
    

Use pcolor or surf, depending on your needs. Hope it helps!

Sita answered 23/7, 2014 at 8:10 Comment(0)
D
1

Matlab has provided code for a function newclim which solves this problem cleanly by concatenating the colormaps into one colormap. I could only find this documentation on the 2012b Help, but not online.

Note that the axes used to update the CLim as the last step could be axes to surf plots, which is how I applied this code.

Calculating Color Limits

The key to this example is calculating values for CLim that cause each surface to use the section of the colormap containing the appropriate colors.

To calculate the new values for CLim, you need to know

  • The total length of the colormap (CmLength)

  • The beginning colormap slot to use for each axes (BeginSlot)

  • The ending colormap slot to use for each axes (EndSlot)

  • The minimum and maximum CData values of the graphic objects contained in the axes. That is, the values of the axes CLim property determined by MATLAB when CLimMode is auto (CDmin and CDmax).

First, define subplot regions and plot the surfaces.

im1 = load('cape.mat');
im2 = load('flujet.mat');
ax1 = subplot(1,2,1); 
imagesc(im1.X) 
axis(ax1,'image')
ax2 = subplot(1,2,2);
imagesc(im2.X) 
axis(ax2,'image')

Concatenate two colormaps and install the new colormap.

colormap([im1.map;im2.map])

Obtain the data you need to calculate new values for CLim.

CmLength   = length(colormap);   % Colormap length
BeginSlot1 = 1;                  % Beginning slot
EndSlot1   = length(im1.map);    % Ending slot
BeginSlot2 = EndSlot1 + 1; 
EndSlot2   = CmLength;
CLim1      = get(ax1,'CLim');  % CLim values for each axis
CLim2      = get(ax2,'CLim');

Defining a Function to Calculate CLim Values

Computing new values for CLim involves determining the portion of the colormap you want each axes to use relative to the total colormap size and scaling its Clim range accordingly. You can define a MATLAB function to do this.

function CLim = newclim(BeginSlot,EndSlot,CDmin,CDmax,CmLength)
   %                Convert slot number and range
   %                to percent of colormap
   PBeginSlot    = (BeginSlot - 1) / (CmLength - 1);
   PEndSlot      = (EndSlot - 1) / (CmLength - 1);
   PCmRange      = PEndSlot - PBeginSlot;
   %                Determine range and min and max 
   %                of new CLim values
   DataRange     = CDmax - CDmin;
   ClimRange     = DataRange / PCmRange;
   NewCmin       = CDmin - (PBeginSlot * ClimRange);
   NewCmax       = CDmax + (1 - PEndSlot) * ClimRange;
   CLim          = [NewCmin,NewCmax];
end

The input arguments are identified in the bulleted list above. The function first computes the percentage of the total colormap you want to use for a particular axes (PCmRange) and then computes the CLim range required to use that portion of the colormap given the CData range in the axes. Finally, it determines the minimum and maximum values required for the calculated CLim range and returns these values. These values are the color limits for the given axes.

Using the Function

Use the newclim function to set the CLim values of each axes. The statement

set(ax1,'CLim',newclim(BeginSlot1,EndSlot1,CLim1(1),...
        CLim1(2),CmLength))

sets the CLim values for the first axes so the surface uses color slots 65 to 120. The lit surface uses the lower 64 slots. You need to reset its CLim values as well.

set(ax2,'CLim',newclim(BeginSlot2,EndSlot2,CLim2(1),...
        CLim2(2),CmLength))

How the Function Works

MATLAB enables you to specify any values for the axes CLim property, even if these values do not correspond to the CData of the graphics objects displayed in the axes. The minimum CLim value is always mapped to the first color in the colormap and the maximum CLim value is always mapped to the last color in the colormap, whether or not there are really any CData values corresponding to these colors. Therefore, if you specify values for CLim that extend beyond the object's actual CData minimum or maximum, MATLAB colors the object with only a subset of the colormap.

The newclim function computes values for CLim that map the graphics object's actual CData values to the beginning and ending colormap slots that you specify. It does this by defining a "virtual" graphics object having the computed CLim values.

Derr answered 20/2, 2015 at 17:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.