scatter3, stop the color changing after a second scatter3 command

I am having some problems with scatter3, this is an example code:
figure
colormap jet
a = scatter3([1 2 3], [1 2 3],[1 2 3], 50, [1; 2; 2], 'filled')
hold on
scatter3([0 1 2], [1 2 3],[1 2 3], 50, [1; 2; 3], 'filled')
hold off
After the second scatter3 command the colors of the first scatter change accordingly. I want to remove this effect. How can I do so?
Thank you!

4 Comments

Thank you both for your answers, I understood what the problem is. I will select the first answer just because it was published first.
Maybe I should make another post but I will write the following expansion here. The original problem is that I wanted to map the norm of a vector to a colour, so that bigger norms corresponded to red and small norms corresponded to blue. My initial approach was as follows:
colors = jet(length(normvec))
normvec = sort(normvec)
scatter3(comp1, comp2, comp3, 10, colors, 'filled')
However, in this way, really similar values still get quite different colours since the jet function generates them at a certain interval that has a fixed size (the problem is more relevant when a small data set is used).
For this reason, I tried to define the colours giving my norm vector directly and let Matlab do the job. Then however incurred the problem I showed you in the original post. The caxis command seems to be the solution to my problem, however, it still annoys me that if you have only two values, these are mapped to the extremes of the colormap (even though they have the same value). If you have a better solution to the 'original' problem I would really appreciate it.
colormap(parula);
scatter3(comp1, comp2, comp3, 10, normvec, 'filled')
caxis([0 maximum_norm_value_to_map]);
where maximum_norm_value_to_map would be the value beyond which you did not want to change colors with increasing norm. The idea is that maximum_norm_value_to_map would be some absolute maximum, and then colors would be mapped on an absolute scale, so that if you looked at two different plots with two different ranges of norms, then the same color would correspond to the same absolute norm value (not to the same relative proportion of the local maximum for that plot.)
That's great thank you! It works perfectely.
A final comment for anybody who needs it: the linear mapping that matlab does is useful but it applies to all the colors of the image. I wrote a short code which returns the same rgb matrix that matlab effectively uses automatically, in this way different colormap limits can be used for different scatter commands.
norms = vecnorm(uvw(:, 1:3), 2, 2);
resolution = 256;
colors = jet(resolution); % the chosen colormap with chosen resolution
Mid = norms; % the middle values you want to assign a color to
Min = 0; % your defined minimum
Max = max(Mid); % your defined maximum
indexes = round(((Mid - Min) ./ (Max)) * (resolution - 1)) + 1; % the indexes which refer to the colors matrix
scatter3(uvw(:, 1), uvw(:, 2), uvw(:, 3), 10, colors(indexes, :), 'filled');

Sign in to comment.

 Accepted Answer

When you use scatter3() and pass in a vector of color information, the information you pass in is not color indices into the current colormap. Instead, the data is interpreted according to the current color axis; see https://www.mathworks.com/help/matlab/ref/caxis.html and https://www.mathworks.com/help/matlab/creating_plots/change-mapping-of-data-values-into-the-colormap.html . For scatter3() there is no CDataMapping property: you should intepret CDataMapping in the case of vector of color values as if CDataMapping were 'scaled' .
When you add the original data in range 1 to 2, the min and max are used to set the caxis. The minimum value (1) is mapped to the first entry in the color map, and the maximum value (2) is mapped to the last entry in the colormap.
When you add the additional data with color info, the min and max of all the data in the axis is used, so the caxis expands to [1 3] . The min value (1) maps to the first entry, the max value (3) maps to the last entry, and the 2 values interpolate over [1 3] and so map to the middle of the color map.
When you say that you do not want the colors of the first scatter to change, that could be interpreted as saying that you want the 1's to map to the first color, and you want the 2's to continue to map to the last color, and you want the 3's to map to.... it isn't clear what you would want them to map to?
If you are doing some kind of presentation over time where you want to show the first version and let the user see it, and then show the second version, and what you are concerned about is consistency over time rather than about the exact colors, then there are multiple approaches:
  • Before doing the first scatter3(), do a caxis() call that gives the minimum and maximum of all of the data you are going to plot. That will set axes CLimMode to 'manual' and so the 1 and 2 of the original scatter3 will already be color interpolated over the entire range, so the mapping will be consistent over time; Or
  • switch to supplying RGB colors for each color instead of a vector of color values. rescale() and ind2rgb() can help with that.

More Answers (1)

This might be a bit tricky to explain what is happening. By specifying C as a vector, the following method is used to determine the color.
  • If C is a vector with length equal to the length of X, Y, and Z, then the values in C are linearly mapped to the colors in the current colormap.
What the actual color is depends on what the current colormapping is. Dy default, the colormap is applied to the range of your color data. When you plot the first scatter3 plot, your color values range from 1 to 2. You can see this if you turn on the colorbar.
scatter3([1 2 3], [1 2 3],[1 2 3], 50, [1; 2; 2], 'filled')
colormap jet
colorbar
What happens is that, when you add your second plot, the range of your color data changes to 1-3. The colormap is rescaled to include the new data, now making 3 dark red, and moving 2 into the center of the range, changing all points with C==2 to green.
figure
scatter3([1 2 3], [1 2 3],[1 2 3], 50, [1; 2; 2], 'filled')
hold on
scatter3([0 1 2], [1 2 3],[1 2 3], 50, [1; 2; 3], 'filled')
hold off
colormap jet
colorbar
There are two ways I can think of to fix this.
  1. Use caxis to set the color range up front
  2. Specify rgb values for your colors rather than the vector approach you are using.
% Method 1 - caxis
figure
scatter3([1 2 3], [1 2 3],[1 2 3], 50, [1; 2; 2], 'filled')
colormap jet
colorbar
caxis([1 3])
% Method 2 - RGB
figure
cmap=[0 0 1;0 1 0;1 0 0];
scatter3([1 2 3], [1 2 3],[1 2 3], 50, cmap([1;2;2],:), 'filled')
hold on
scatter3([0 1 2], [1 2 3],[1 2 3], 50, cmap([1;2;3],:), 'filled')
hold off
colormap jet

Products

Release

R2021a

Community Treasure Hunt

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

Start Hunting!