How to change the way data is scaled to custom colormap in a scatter plot.

Hello,
I've been searching and can't figure out the answer to my specific problem. I am creating scatter plots with over 2K plot points. I am creating 20 different ones that each correspond to a different condition in my data. I am capturing each figure with 'getframe' and then making a movie out of all the plots.
Each plot contains a different range of values, but generally the data spans from a negative value to a positive value. This could be something like -10:8 or -80:65. It's varied throughout the data. I want my colormap to go from red to white for negative values and white to blue for positive values. My custom colormap is basically just RGB values that would produce red to white to blue, but I can't figure out how to apply it to each set of data so that the white is centered around the value closest to 0. I can open up the colormap editor and do it manually by moving the center node, but if I look at the colormap afterward, it doesn't change the values at all. I've looked through the entries in gcf to see if I could figure out what it's changing, but I can't. I've put my code for constructing the images and the colormap below. This is a work in progress, so I know it can be optimized(and obviously some of the variables I refer to are preloaded), but that's for later on. I'm really just trying to get the basics down right now. Any help would be appreciated. Thanks!
loops = 20;
F(loops) = struct('cdata',[],'colormap',[]);
for j = 1:length(loops);
betas = v1betas(:,j);
goodbetas = [betas(goodind),goodind];
sorted = sortrows(goodbetas,1);
plotvals = zeros(length(sorted),2);
for i= 1:length(sorted)
p = sorted(i,2);
plotvals(i,1) = v1ecc(p) * cos(v1ang(p)/180*pi);
plotvals(i,2) = v1ecc(p) * sin(v1ang(p)/180*pi);
end
c = sorted(:,1);
figure;
scatter(plotvals(:,1),plotvals(:,2),40,c,'filled'),colorbar;
colormap(map);
axis([-50 50 -50 50]);
F(j)=getframe(gcf);
close Figure 1;
end
%code for color map:
map = zeros(100,3);
map(1:50,1) = 1;
map(50:100,1) = linspace(1,0,51);
map(50:100,2) = linspace(1,0,51);
map(50:100,3) = 1;
map(1:50,2) = linspace(0,1,50);
map(1:50,3) = linspace(0,1,50);

Réponses (1)

Hi,
One solution is to set the CLim values for the axis to be equal positive and negative values. The white section of your colormap will then always be centred. This may be suitable if you want to represent the magnitude of the data equally for positive and negative values with respect to their colour.
figure;
scatter(plotvals(:,1),plotvals(:,2),40,c,'filled'),colorbar;
colormap(map);
axis([-50 50 -50 50]);
hAx = gca;
maxLimit = max(abs(c));
hAx.CLim = [-1*maxLimit maxLimit]; %
F(j)=getframe(gcf);
close Figure 1;
Alternatively, you may want to modify the length of the red and blue sections of the colormap depending on the magnitude of the maximum positive and negative values. For example, if the maximum negative value is -5 and the maximum positive value is 10, the red section of the colormap should be twice as long as the blue section. With CLim equal to [-5 10], the white should then be centred at 0.
Henry

5 commentaires

Thanks for the reply. Unfortunately neither of these solutions seem to work for me. I need my colormap to reflect the actual numbers in my data, so I cannot set the negative value to be the same as the positive value, as this does not reflect the real data value.
The second solution you mentioned doesn't actually center the white around 0. The way I have done the scatter plot automatically scales to have the Clim equal to the minimum and maximum of the data, this does not change the length of the red and blue sections. So the white is centered at the center point of the data range, which is not always 0.
The Colormap will still represent your data, just that the limits of the colour axis will extend beyond the limits of your data. For example:
data = [-5:10];
figure;
scatter(1:16,zeros(16,1),40,data,'filled')
colorbar
hAx = gca
hAx.CLim = [-10 10];
The second solution will map values of 0 to the white part of the colormap, but the white section will not be in the centre. If what you want is a colormap where the red half extends from the most negative number and the blue half to the most positive number, then you will probably have to normalize your colour data.
For example:
data = [-5:10];
% Negative Values
negVals = data(data < 0);
maxNeg = max(abs(negVals));
normalizedNegative = negVals/maxNeg;
% Positive Values
posVals = data(data >= 0);
maxPos = max(abs(posVals));
normalizedPositive = posVals/maxPos;
normalized_C_Data = [normalizedNegative normalizedPositive];
figure;
scatter(1:16,zeros(16,1),40,normalized_C_Data,'filled')
cbar = colorbar
The problem here is that the tick values on your colorbar are now going to be between -1 and 1. You will then have to change the colorbar TickLabels property to map correctly to your positive and negative data range. Following on from the above example:
cbar.Ticks = [-1 -0.5 0 0.5 1];
cbar.TickLabels = {-5 -2.5 0 5 10};
Note that this uses the same colormap as you posted in your original question
Unless I'm missing something, I don't see how the second solution will map values of 0 to the white part of the colormap.
For instance, if I use this code:
hAx = gca;
maxLim = max(max(c));
minLim = min(min(c));
hAx.CLim = [minLim maxLim];
I do not get the white section off center. I get the attached plot where the white section is centered in my data.
Hi MMM,
Yes, the second solution in my original answer would involve modifying the colormap so that the proportion of the red/blue sections represent the magnitude of your positive/negative data.
So, keeping it simple, with my case of data that ranges from -5:10
map = zeros(99,3);
map(1:33,1) = 1;
map(34:99,1) = linspace(1,0,66);
map(34:99,2) = linspace(1,0,66);
map(34:99,3) = 1;
map(1:33,2) = linspace(0,1,33);
map(1:33,3) = linspace(0,1,33);
C = -5:10;
scatter(1:16,zeros(16,1),40,C,'filled')
colorbar
colormap(map)
Hope that makes a bit more sense? I dont imagine it is the solution you actually want however as it means re calculating your colormap every time you plot the data, and it will look different depending on what the limits of your C data is. (I have also uploaded a figure to my previous comment to illustrate the results you get from normalising your C data).
Also, there is one other way in which you could scale the colorbar, by setting the CAxis limits to be equal, and then clipping the colorbar limits to your data range:
C = -5:10;
scatter(1:16,zeros(16,1),40,C,'filled')
hAx = gca;
cbar = colorbar;
colormap(map) %your original map...
hAx.CLim = [-10 10];
cbar.Limits = [-5 10];

Connectez-vous pour commenter.

Catégories

En savoir plus sur Color and Styling dans Centre d'aide et File Exchange

Question posée :

MMM
le 4 Sep 2016

Commenté :

le 6 Sep 2016

Community Treasure Hunt

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

Start Hunting!

Translated by