creating legend for scatter3 plot (Matlab) - matlab

I have a matrix points X in 3 dimensions (X is a Nx3 matrix) and those points belong to clusters. The cluster it belongs is given by the Nx1 vector Cluster (it has values like 1,2,3,...). So, I am plotting it on scatter3 like this:
scatter3(X(:,1),X(:,2),X(:,3),15,Cluster)
It works fine, but I would like to add a legend to it, showing the colored markers and the cluster it represents.
For example, if i have 3 clusters, I would like to have a legend like:
<blue o> - Cluster 1
<red o> - Cluster 2
<yellow o> - Cluster 3
Thank you very much for the help!

Instead of using scatter3, I suggest you use plot3, which will make labeling much simpler:
%# find out how many clusters you have
uClusters = unique(Cluster);
nClusters = length(uClusters);
%# create colormap
%# distinguishable_colormap from the File Exchange
%# is great for distinguishing groups instead of hsv
cmap = hsv(nClusters);
%# plot, set DisplayName so that the legend shows the right label
figure,hold on
for iCluster = 1:nClusters
clustIdx = Cluster==uClusters(iCluster);
plot3(X(clustIdx,1),X(clustIdx,2),X(clustIdx,3),'o','MarkerSize',15,...
'DisplayName',sprintf('Cluster %i',uClusters(iCluster)));
end
legend('show');

Either you use
legend
Code:
h = scatter3(X(:,1),X(:,2),X(:,3),15,Cluster)
hstruct = get(h);
legend(hstruct.Children, "Cluster1", "Cluster2", "Cluter3");
or
annotation.

Related

plot an mdscaled matrix of points

I have a 151-by-200 matrix, let's say D, where rows are patients and cols are some features.
After using pdist and mdscale I obtain a 151-by-3 matrix. I also used some consensus clustering algorithm and obtained the partitioning of the patients.
Now I would like to plot the distribution of the mdscaled matrix of points, each one with a shape and a colour (where shapes indicates classes and colors clusters ) as in the image below.
Can you give me an hint on how to do it? Thank you.
Here is an example how to plot grouped 3D points:
% data and clusters
load fisheriris
X = meas(:,1:3);
[L,~,Y] = unique(species);
% colors and markers of each group
colors = hsv(numel(L));
markers = 'osdv^x*+.><ph';
% plot
for i=1:numel(L)
ind = (Y == i);
h(i) = line(X(ind,1), X(ind,2), X(ind,3), ...
'LineStyle','none', 'LineWidth',1, 'MarkerSize',8, ...
'Marker',markers(i), 'Color',colors(i,:), ...
'MarkerEdgeColor','k', 'MarkerFaceColor',colors(i,:));
end
view(-150,30), axis vis3d, grid on, box on
legend(h, L, 'Location','northeast')
title('MultiDimensional Scaling')
xlabel('dim1'), ylabel('dim2'), zlabel('dim3')
You can customize the shapes and colors to match your criteria ("shapes indicates classes and colors clusters").

How to make 2D scatter plot in Matlab with colors depending on values?

I have three vectors of the same lenght: x, y, and cls. I want to make a 2D plot of x and y but each point should have a color corresponding to the value of cls.
I thought about using the scatter function but you can chage the color of the whole plot, not of particular elements. Any ideas?
I would like to get something like in this example, when cls has elements of three values:
From the help of scatter:
scatter(x,y,a,c) specifies the circle colors. To plot all circles with the same color, specify c as a single color string or an RGB triplet. To use varying color, specify c as a vector or a three-column matrix of RGB triplets.
you can construct c as
c=zeros(size(x),3);
c(cls==1,:)=[1 0 0]; % 1 is red
% ...
scatter(x,y,1,c)
However, I dont know how to do the background. Did you apply some Machine learning algorithm to clasify the data? maybe you can get the equations to plot the background from there, but it depends on the method.
If you have the Statistics Toolbox, there is an easy way of doing this, it's called gscatter.
It takes similar inputs to scatter, but the third input is the group:
gscatter(x,y,cls)
You can add colours and markers - this plots with red, then green, then blue (order determined by the contents of cls, all markers circles.
gscatter(x,y,cls,'rgb','o')
Here's another solution splitting your data in three using logical indexing:
% Some random data
x = rand(100,1);
y = rand(100,1);
cls = round(2*rand(100,1));
% Split the data in three groups depending on the value in cls
x_red = x(cls==0);
y_red = y(cls==0);
x_green = x(cls==1);
y_green = y(cls==1);
x_blue = x(cls==2);
y_blue = y(cls==2);
% plot the data
scatter(x_red,y_red,1,'r')
hold on
scatter(x_green,y_green,1,'g')
scatter(x_blue,y_blue,1,'b')
hold off
One very simple solution with c being the color vector:
scatter3(X,Y,zeros(size(X,1)),4,c);
view(0,90);

Displaying multiple figures with differents colors

I have a matlab code that generates 3D points , so I want to plot each 3D point with different colors.
My last code for generat all points are
figure(i),plot3(mx,my,mz,'r*');
and this one plot all peaks but with same color which are red.
instead of figure(i),plot3(mx,my,mz,'r*'); you can plot each datapoint separately and assign a different color using the property 'Color' of the plot3.
such an example would be:
figure(i),hold on
for j=1:length(mx)
plot3(mx(j),my(j),mz(j),'Color',rand(1,3));
end
hold off
The way each point is coloured is up to you just change the rand to something that makes sense.
What about using e.g. hsv:
M = length(mx);
cols = hsv(M); % specify M colors by hsv
figure(i);
hold on;
for pIdx = 1:M
plot3(mx(pIdx),my(pIdx),mz(pIdx),'Color',cols(pIdx,:));
end

Plot data with MATLAB biplot with more than 1 color

I have 3 groups of data that had PCA performed on them as one group. I want to highlight each variable group with a different color. Prior to this I overlaid 3 biplots. This gives different colors but creates a distortion in the data as each biplot function skews the data. This caused the groups to all be skewed by different amounts, making the plot not a correct representation.
How do I take a PCA scores matrix (30x3) and split it so the first 10x3 is one color, the next 10x3 is another and the third 10x3 is another, without the data being skewed?
"Skewing" is happening because biplot is renormalizing the scores so the farthest score is distance 1 . axis equal isn't going to fix this. You should use scatter3 instead of biplot
data = rand(30,3);
group = scores(1:10,:)
scatter3(group(:,1), group(:,2), group(:,3), '.b')
hold all
group = scores(11:20,:)
scatter3(group(:,1), group(:,2), group(:,3), '.r')
group = scores(21:30,:)
scatter3(group(:,1), group(:,2), group(:,3), '.g')
hold off
title('Data')
xlabel('X')
ylabel('Y')
zlabel('Z')
Or modify your code's scatter3 lines so that the markers are different colors. The parameter after 'marker' tells what symbol and what symbol and color to plot. E.g. '.r' is a red dot. See Linespec for marker and color parameters.
scatter3(plotdataholder(1:14,1),plotdataholder(1:14,2),plotdataholder(1:14,3),35,[1 0 0],'marker', '.b');
hold on;
scatter3(plotdataholder(15:28,1),plotdataholder(15:28,2),plotdataholder(15:28,3),35,[0 0 1],'marker', '.r') ;
scatter3(plotdataholder(29:42,1),plotdataholder(29:42,2),plotdataholder(29:42,3),35,[0 1 0],'marker', '.g');
This is the method I used to plot biplot data with different colors. The lines of code prior to plot are taken from the biplot.m file. The way biplot manipulates data is kept intact and stops skewing of data when using overlaid biplots.
This coding is not the most efficient, one can see parts that can be cut. I wanted to keep the code intact so one can see how biplot works in it's entirety.
%%%%%%%%%%%%%%%%%%%%%
xxx = coeff(:,1:3);
yyy= score(:,1:3);
**%Taken from biplot.m; This is alter the data the same way biplot alters data - having the %data fit on grid axes no larger than 1.**
[n,d2] = size(yyy);
[p,d] = size(xxx); %7 by 3
[dum,maxind] = max(abs(xxx),[],1);
colsign = sign(xxx(maxind + (0:p:(d-1)*p)));
xxx = xxx .* repmat(colsign, p, 1);
yyy= (yyy ./ max(abs(yyy(:)))) .* repmat(colsign, 42, 1);
nans = NaN(n,1);
ptx = [yyy(:,1) nans]';
pty = [yyy(:,2) nans]';
ptz = [yyy(:,3) nans]';
**%I grouped the pt matrices for my benefit**
plotdataholder(:,1) = ptx(1,:);
plotdataholder(:,2) = pty(1,:);
plotdataholder(:,3) = ptz(1,:);
**%my original score matrix is 42x3 - wanted each 14x3 to be a different color**
scatter3(plotdataholder(1:14,1),plotdataholder(1:14,2),plotdataholder(1:14,3),35,[1 0 0],'marker', '.');
hold on;
scatter3(plotdataholder(15:28,1),plotdataholder(15:28,2),plotdataholder(15:28,3),35,[0 0 1],'marker', '.') ;
scatter3(plotdataholder(29:42,1),plotdataholder(29:42,2),plotdataholder(29:42,3),35,[0 1 0],'marker', '.');
xlabel('Principal Component 1');
ylabel('Principal Component 2');
zlabel('Principal Component 3');
I am not sure if it will help, but try axis equal after you have overlaid the plots.

MATLAB: draw centroids

My main question is given a feature centroid, how can I draw it in MATLAB?
In more detail, I have an NxNx3 image (an RGB image) of which I take 4x4 blocks and compute a 6-dimensional feature vector for each block. I store these feature vectors in an Mx6 matrix on which I run kmeans function and obtain the centroids in a kx6 matrix, where k is the number of clusters and 6 is the number of features for each block.
How can I draw these center clusters in my image in order to visualize if the algorithm is performing the way I wish it to perform? Or if anyone has any other way/suggestions on how I can visualize the centroids on my image, I'd greatly appreciate it.
Here's one way you can visualize the clusters:
As you described, first I extract the blocks, compute the feature vector for each, and cluster this features matrix.
Next we can visualize the clusters assigned to each block. Note that I am assuming that the 4x4 blocks are distinct, this is important so that we can map the blocks to their location back in the original image.
Finally, in order to display the cluster centroids on the image, I simply find the closest block to each cluster and display it as a representative of that cluster.
Here's a complete example to show the above idea (in your case, you would want to replace the function that computes the features of each block by your own implementation; I am simply taking the min/max/mean/median/Q1/Q3 as my feature vector for each 4x4 block):
%# params
NUM_CLUSTERS = 3;
BLOCK_SIZE = 4;
featureFunc = #(X) [min(X); max(X); mean(X); prctile(X, [25 50 75])];
%# read image
I = imread('peppers.png');
I = double( rgb2gray(I) );
%# extract blocks as column
J = im2col(I, [BLOCK_SIZE BLOCK_SIZE], 'distinct'); %# 16-by-NumBlocks
%# compute features for each block
JJ = featureFunc(J)'; %'# NumBlocks-by-6
%# cluster blocks according to the features extracted
[clustIDX, ~, ~, Dist] = kmeans(JJ, NUM_CLUSTERS);
%# display the cluster index assigned for each block as an image
cc = reshape(clustIDX, ceil(size(I)/BLOCK_SIZE));
RGB = label2rgb(cc);
imshow(RGB), hold on
%# find and display the closest block to each cluster
[~,idx] = min(Dist);
[r c] = ind2sub(ceil(size(I)/BLOCK_SIZE), idx);
for i=1:NUM_CLUSTERS
text(c(i)+2, r(i), num2str(i), 'fontsize',20)
end
plot(c, r, 'k.', 'markersize',30)
legend('Centroids')
The centroids do not correspond to coordinates in the image, but to coordinates in the feature space. There is two ways you can test how well kmeans performed. For both ways, you want to fist associate the points with their closest cluster. You get this information from the first output of kmeans.
(1) You can visualize the clustering result by reducing the 6-dimensional space to 2 or 3-dimensional space and then plotting the differently classified coordinates in different colors.
Assuming that the feature vectors are collected in an array called featureArray, and that you asked for nClusters clusters, you'd do the plot as follows using mdscale to transform the data to, say, 3D space:
%# kmeans clustering
[idx,centroids6D] = kmeans(featureArray,nClusters);
%# find the dissimilarity between features in the array for mdscale.
%# Add the cluster centroids to the points, so that they get transformed by mdscale as well.
%# I assume that you use Euclidean distance.
dissimilarities = pdist([featureArray;centroids6D]);
%# transform onto 3D space
transformedCoords = mdscale(dissimilarities,3);
%# create colormap with nClusters colors
cmap = hsv(nClusters);
%# loop to plot
figure
hold on,
for c = 1:nClusters
%# plot the coordinates
currentIdx = find(idx==c);
plot3(transformedCoords(currentIdx,1),transformedCoords(currentIdx,2),...
transformedCoords(currentIdx,3),'.','Color',cmap(c,:));
%# plot the cluster centroid with a black-edged square
plot3(transformedCoords(1:end-nClusters+c,1),transformedCoords(1:end-nClusters+c,2),...
transformedCoords(1:end-nClusters+c,3),'s','MarkerFaceColor',cmap(c,:),...
MarkerEdgeColor','k');
end
(2) You can, alternatively, create a pseudo-colored image that shows you what part of the image belongs to which cluster
Assuming that you have nRows by nCols blocks, you write
%# kmeans clustering
[idx,centroids6D] = kmeans(featureArray,nClusters);
%# create image
img = reshape(idx,nRows,nCols);
%# create colormap
cmap = hsv(nClusters);
%# show the image and color according to clusters
figure
imshow(img,[])
colormap(cmap)