简体   繁体   中英

Produce a 3D stem plot with a custom colormap in MATLAB

I have a matrix (200 x 4) where first 3 values are X , Y and Z data. I want use the fourth column to display each (X,Y,Z) triplet so that it maps to a color.

The fourth column contains values from 0.0 to 1.0 (200 values). I want to map these values with colormap manually and linearly. The smallest value should have blue color and the largest value may have red color.

I know that it is possible with scatter3 . However, I want to do using stem3 where I can specify the color manually from colormap.

Is there a way to do this in MATLAB?

That's pretty simple to do. kkuilla posted a very insightful link. To get something started, if you want to have a colour map that varies from blue to red, you know that an image is decomposed into three colours: Red, green and blue.

Therefore, all you would have to do is vary the red and blue channels. Start with a pure blue colour, which is RGB = (0,0,255) where this is mapped to the initial weight of w = 0 and vary this to the end where RGB = (255,0,0) with w = 1 . You can very easily do that by linspace . However, colours in a colour map for plotting in MATLAB are normalized so that they're between [0,1] , not [0,255] . Also, because a colour map in MATLAB is a matrix of N x 3 , where N is the total number of colours you want, all you have to do is:

num_colours = 10;
colourmap = [linspace(0,1,num_colours).' zeros(num_colours,1) linspace(1,0,num_colours).'];
weights = linspace(0,1,num_colours);

num_colours is the total number of colours you would like displayed. I set it to 10 to get you started. weights is something we will need for later, so don't worry about that righ tnow. Essentially, colormap would be the colour map you apply to your data.

However, what is going to be difficult now is that the data that you're plotting has no correlation to the weight of the data itself (or the fourth column of your data). This means that you can't simply use the (X,Y,Z) data to determine what the colour of each plot in your stem is going to look like. Usually for colour maps in MATLAB, the height of the stem is proportional to the colour that is displayed. For the largest Z value in your data, this would naturally be assigned to the colour at the end of your colour map, or red. The smallest Z value in your data would naturally get assigned at the beginning of your colour map, or blue.

If this was the case, you would only need to make one stem call and specify the colour map as the attribute for Color . Because there is no correlation between the height of the Z value and the weight that you're assigning for each data point, you have no choice but to loop through each of your points and determine the closest value between the weight for a point with every weight and ultimately every colour in your colour map, then apply this closest colour to each point in your stem respectively.

We determine the closest point by using the weights vector that was generated above. We can consider each colour as having a mapping from [0,1] , and each weight corresponds to the colour in colourmap . Therefore, a weight of 0 is the first colour in the colour map, and that's in the first row. The next weight after this is the second colour, and that's in the second row and so on.... so we simply need to determine where each weight that's in the fourth column of your matrix is closest to for the above weights vector. This will determine which colour we need to select from the colour map to plot the point.

Given that your matrix of 200 x 4 is stored in data , you must specifically do this:

%// Spawn a new figure
figure;
%// Determine the number of points in the dataset
num_points = size(data,1);
%// For each point in the data set
for idx = 1 : num_points
    %// Get 4th column element and determine closest colour
    w = data(idx,4);
    [~,ind] = min(abs(weights-w));
    color = colourmap(ind,:);

    %// Plot a stem at this point and change the colour of the stem
    %// as well as the marker edge colour and face colour       
    stem3(data(idx,1), data(idx,2), data(idx,3), 'Color', color, ...
         'MarkerEdgeColor', color, 'MarkerFaceColor', color);

    %// Make sure multiple calls to stem don't clear the plot
    hold on;
end

%// Display colour bar to show colours
colormap(colourmap(1:end-1,:));
colorbar('YTickLabel', colourmap);

The last two lines are a bit hackish, but we basically show a colour bar to the right of the plot that tells you how each weight maps to each colour.


Let's test this on some data. I'm going to generate a random 200 x 4 matrix of points and we will use the above code and plot it using stem3 :

rng(123123); %// Set seed for reproducibility
data = rand(200,4);
num_colours = 10;

I set the total number of unique colours to 10. Once I have this above data, when I run through the code above, this is the plot I get:

在此处输入图片说明

You can use HSV as well. The Z values would correspond to your fourth column. Low Z values are blue and high Z values are red.

在此处输入图片说明

I used the site http://colorizer.org/ to work out that blue is H=0.65 and red is H=1 . S and V stay the same.

From http://colorizer.org/ , I got that a blue colour is H=236, S=100, V=100 . Then the H value for blue is H = 235/360 = 0.65 and H=1, S=1, V=1 for red.


num_elem = 200;
c = linspace(0,1,num_elem)'; % // Replace this with the values from your fourth column


% // The equation gives blue (H=0.65) for c=0 and red (H=1) for c = 1
H = 0.65 + ((1-0.65).* c); 
S = ones(size(c,1),1);
V = ones(size(c,1),1);

% // You have to convert it to RGB to be compatible with stem3

colourmap = hsv2rgb([H,S,V]);


% // Generate some sample data
theta = linspace(0,2*pi,num_elem)';
X = cos(theta);
Y = sin(theta);
Z = theta;

% // Plot the sample data with the colourmap
figure;
hold on;
for idx=1:num_elem
  stem3(X(idx),Y(idx),Z(idx),':*','Color',colourmap(idx,:) ...
  ,'MarkerEdgeColor',colourmap(idx,:) ...
  ,'MarkerFaceColor',colourmap(idx,:) ...
  ,'LineWidth',4 ...
  );
end

hold off;
set(gca,'FontSize',36');

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM